今天做JSOI2012的题。
才120,其实是可以拿很多部分分什么的,但是都打错。。。
(代码实现能力太差了。
1、
4330: JSOI2012 爱之项链
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 50 Solved: 24Description
在进香河,流传着这样一段美丽的故事。zyg与kzn是两个生活在进香河的孩子,一天,他们两人闹矛盾了,于是zyg送给了kzn一条精美的爱之项链。从此他们幸福生活在一起。
这则故事的真实性到今天已经没有意义了,然而我们关注的是那一条精美的爱之项链。这是一条由N个精致的戒指与一块特殊纪念品相连而成的环形,如下图中的爱心符号正是一种特殊纪念品。(据说是2012年情人节时zyg特意托人订制的)上面的每一枚戒指又是由M个带磁性的特殊彩色球状物组成的环形。也许你会认为,这所谓的戒指,更像是一条条小项链。
下图给出了一种可行的方案,其中左边描述的是单一的一枚戒指,右图描述的是项链。
这里,所有带磁性的特殊彩色球状物的颜色只有R种,这里我们用1到R来表示。如果一枚戒指可以通过顺时针或逆时针的旋转后与另外一枚戒指相同,则认为这是两枚相同的戒指。
对于一条爱之项链,要求满足任何相邻两枚戒指必须是不相同的。同时,特殊纪念品左右两枚戒指也必须是不同的。
现在给定N,M和R,问究竟有多少种不同的爱之项链。
注意:
1、特殊纪念品的插入位置不同,也许会得到不同的爱之项链。
2、这里我们只考虑旋转后是否相同,不考虑翻转操作,这一点不论是对于每一枚戒指,还是对于整条项链,都是这样的。
Input
一行,三个正整数,分别是N,M和R。
Output
一行,表示有多少种不同的爱之项链。你只需要将答案模3214567。
Sample Input
10 5 4
Sample Output
1398595
HINT
对于100%的数据,N<=10^15,M<=10^9,R<=10^6。
应上传者要求,此题不公开,如有异议,请提出.
Source
挺裸的置换的。
首先算戒指有多少种
$\sum_{i=1}^{m} R^{gcd(i,m)}$
$=\sum_{d|n}R^d*\varphi(d)$
不动点方案数记得最后除以m!!!!
考场上竟然觉得要杜教筛才能过,但是不会,就直接用第一条式子打80分的,后面那个也是没有矩乘了,【然而还是没用LL搞到没什么分哭死。。
其实枚举n的约数就好了,不会超过$\sqrt{n}$个。
然后串项链,可以把环断成链,要求相邻的不同且首尾不同
$f[i]$表示串$i$个首尾不一定不相同的方案
$dp[i]$表示串$i$个首尾不同的方案【都要满足相邻的不同】
假设第一步算到有c种戒指
$f[i]=f[i-1]*(c-1)$
$dp[i]=dp[i-1]*(c-2)+(f[i-1]-dp[i-1])*(c-1)=f[i]-dp[i-1]$
这样子的递推式显然可以用矩阵加速。
还有一个问题是mod挺小的,若m为mod的倍数,就没有逆元,就不能除了。
小山羊说的先模mod^2搞搞??不知道。。数据没有。。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 10000010 8 #define Maxm 1000010 9 #define LL long long 10 const int Mod=3214567; 11 12 int pw[Maxm],f[Maxn],dp[Maxn]; 13 14 int gcd(int a,int b) 15 { 16 if(b==0) return a; 17 return gcd(b,a%b); 18 } 19 20 int qpow(int x,int b) 21 { 22 int ans=1; 23 while(b) 24 { 25 if(b&1) ans=1LL*ans*x%Mod; 26 x=1LL*x*x%Mod; 27 b>>=1; 28 } 29 return ans; 30 } 31 32 LL n; 33 int m,r; 34 int a1,pl=0,pr[Maxm],rr[Maxm]; 35 36 void ffind(int x,int dd,int phi) 37 { 38 if(x==pl+1) 39 { 40 a1=(a1+1LL*qpow(r,m/dd)*phi)%Mod; 41 return; 42 } 43 ffind(x+1,dd,phi); 44 int nw=1; 45 for(int i=1;i<=rr[x];i++) 46 { 47 ffind(x+1,dd*nw*pr[x],phi*(pr[x]-1)*nw); 48 nw*=pr[x]; 49 } 50 } 51 52 struct node 53 { 54 int w[4][4]; 55 }t[5]; 56 57 void mul(int x,int y,int z) 58 { 59 t[3].w[1][1]=t[3].w[1][2]=t[3].w[2][1]=t[3].w[2][2]=0; 60 for(int k=1;k<=2;k++) 61 for(int i=1;i<=2;i++) 62 for(int j=1;j<=2;j++) 63 t[3].w[i][j]=(t[3].w[i][j]+1LL*t[y].w[i][k]*t[z].w[k][j]%Mod)%Mod; 64 for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) t[x].w[i][j]=t[3].w[i][j]; 65 } 66 67 void qpw(LL b) 68 { 69 t[1].w[1][1]=1;t[1].w[1][2]=0; 70 t[1].w[2][1]=0;t[1].w[2][2]=1; 71 while(b) 72 { 73 if(b&1) mul(1,0,1); 74 mul(0,0,0); 75 b>>=1; 76 } 77 } 78 79 int main() 80 { 81 scanf("%lld%d%d",&n,&m,&r); 82 // pw[0]=1; 83 // for(int i=1;i<=m;i++) pw[i]=1LL*r*pw[i-1]%Mod; 84 85 int mm=m; 86 for(int i=2;i*i<=mm;i++) if(mm%i==0) 87 { 88 pr[++pl]=i;rr[pl]=0; 89 while(mm%i==0) rr[pl]++,mm/=i; 90 } 91 if(mm) pr[++pl]=mm,rr[pl]=1; 92 a1=0; 93 ffind(1,1,1); 94 a1=1LL*a1*qpow(m,Mod-2)%Mod; 95 96 t[0].w[1][1]=a1-1;t[0].w[1][2]=0; 97 t[0].w[2][1]=a1-1;t[0].w[2][2]=-1; 98 99 qpw(n-1); 100 int ans=(1LL*t[1].w[2][1]*a1)%Mod; 101 printf("%d\n",(ans%Mod+Mod)%Mod); 102 103 return 0; 104 }
2、
4331: JSOI2012 越狱老虎桥
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 19 Solved: 13
[Submit][Status][Discuss]Description
这里,是美丽的南京;这里,是秀美的进香河;这里是安逸的老虎桥。
如果说进香河的美,美在其秀美的风光,倒不如说是美在了那惬意的南京古典小巷式生活。如果说进香河的迷人,在其淳朴的民风,倒不如说是那被历史掩埋了的秘密吸引着人们好奇的心。
也许很多人都还记得,老虎桥监狱,北洋时期江南最大的监狱,在近一个世纪中,面对满清、北洋、民国、新中国几朝兴衰,名称屡次更替,沧桑尽显其中。
现在的人们,恐怕很难相信,到底有多少惊心动魄的事情曾经就在这里上演。
那是1948年的冬天,南京地下组织的一支小分队决定偷袭老虎桥监狱,救出被困的数百名人员。那时的老虎桥监狱,被N层电网围了起来,由内而外,依次编号为1,2,…,N。第1层电网接有高压电。有M条高压线,连接了所有电网,其中第i条高压线连接了第ai和bi层电网,如果要破坏第i条高压线,需要至少动用Ti位特工。面对这么多层电网,偷袭小分队犯愁了。至少需要破坏一层电网,否则是无法偷袭成功的。
然而,狡猾的间谍却知道了这件事情,为了破坏偷袭计划,敌人秘密地又增加了一条高压线,不让偷袭小分队的成员发现。
为了能够偷袭成功,不论新增的这一条秘密高压线是连接哪两层电网的,小分队都必须要破坏且仅破坏一条高压线,使得至少有一层电网不通电。注意,对于新增的高压线,我们并不知道需要多少位特工才能成功破坏。现在的问题是,偷袭小分队至少需要多少名特工呢?
决战就在今夜!
Input
第一行有2个整数,N和M,分别表示电网层数和高压线个数。
之后M行,每行3个整数,分别是ai, bi和Ti。
Output
输出只有一行,包含一个整数,表示最少需要动用的特工人数。
如果计划必然失败,则输出 -1。
Sample Input
3 2
1 2 1
2 3 2
Sample Output
-1
HINT
对于100%的数据,N<=500000,M<=1000000,T<=100000。
应上传者要求,此题不公开,如有异议,请提出.
Source
考场70分。。但是打了190行然后1h+。。。
哭瞎。。。我真傻,其实没有那么难,我打了点分治。。。不说了。。。
首先边双联通缩点,不是割边最后肯定不割。
然后你肯定先选最小的边纳入不计算的路径的,然后在选次小边,再选。。。当不能构成路径时,就是答案了。
【很显然啊,我当时有想过这里的,但是觉得处理方法不优就没打。。。太傻了。。
没有bac先放70分的代码了,有点小错误的说。。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 500010 8 #define Maxm 1000010 9 #define INF 0xfffffff 10 11 int mymin(int x,int y) {return x<y?x:y;} 12 int mymax(int x,int y) {return x>y?x:y;} 13 14 struct node 15 { 16 int x,y,next,c,p; 17 }t[Maxm*2],tt[Maxn]; 18 int first[Maxn],len; 19 20 void ins(int x,int y,int c) 21 { 22 t[++len].x=x;t[len].y=y;t[len].c=c; 23 t[len].next=first[x];first[x]=len; 24 t[len].p=1; 25 } 26 void ins2(int x,int y,int c) 27 { 28 tt[++len].x=x;tt[len].y=y;tt[len].c=c; 29 tt[len].next=first[x];first[x]=len; 30 } 31 32 int sta[Maxn],sl; 33 int dfn[Maxn],low[Maxn],cnt,bcc[Maxn],bl; 34 void ffind(int x,int ff) 35 { 36 dfn[x]=low[x]=++cnt; 37 sta[++sl]=x; 38 for(int i=first[x];i;i=t[i].next) if(t[i].p) 39 { 40 int y=t[i].y; 41 if(i&1) t[i].p=t[i+1].p=0; 42 else t[i].p=t[i-1].p=0; 43 if(dfn[y]==0) 44 { 45 ffind(y,x); 46 low[x]=mymin(low[x],low[y]); 47 if(low[y]>dfn[x]) 48 { 49 bl++; 50 while(1) 51 { 52 int z=sta[sl--]; 53 bcc[z]=bl; 54 if(z==y) break; 55 } 56 } 57 } 58 else low[x]=mymin(low[x],dfn[y]); 59 } 60 } 61 62 bool vis[Maxn]; 63 int sm[Maxn],mn[Maxn],id[Maxn],mx[Maxn],rt; 64 int fa[Maxn]; 65 void dfs1(int x,int ff,int tot) 66 { 67 sm[x]=1;mx[x]=0; 68 for(int i=first[x];i;i=tt[i].next) if(tt[i].y!=ff&&vis[tt[i].y]) 69 { 70 int y=tt[i].y; 71 dfs1(y,x,tot); 72 sm[x]+=sm[y]; 73 mx[x]=mymax(mx[x],sm[y]); 74 } 75 mx[x]=mymax(mx[x],tot-sm[x]); 76 if(rt==0||mx[x]<mx[rt]) rt=x; 77 } 78 79 int get_3(int x,int ff) 80 { 81 fa[x]=ff; 82 for(int i=first[x];i;i=tt[i].next) if(tt[i].y!=ff&&vis[tt[i].y]) 83 { 84 int y=tt[i].y; 85 mn[y]=tt[i].c;id[y]=y; 86 get_3(y,x); 87 if(mn[x]>mn[y]) 88 { 89 mn[x]=mn[y]; 90 id[x]=id[y]; 91 } 92 } 93 } 94 95 int get_(int x) 96 { 97 int mnn=INF,nid=x; 98 for(int i=first[x];i;i=tt[i].next) if(tt[i].y!=fa[x]&&vis[tt[i].y]) 99 { 100 int y=tt[i].y; 101 if(mn[y]<mnn) mnn=mn[y],nid=y; 102 } 103 if(nid!=x) nid=get_(nid); 104 return nid; 105 } 106 107 int get_2(int x,int rr,int mnn) 108 { 109 if(fa[x]==rr) return mnn; 110 for(int i=first[fa[x]];i;i=tt[i].next) if(tt[i].y!=fa[fa[x]]&&vis[tt[i].y]) 111 { 112 int y=tt[i].y; 113 if(y==x) continue; 114 mnn=mymin(mnn,mn[id[y]]); 115 } 116 return get_2(fa[x],rr,mnn); 117 } 118 119 int ans=0; 120 void dfs2(int x,int ff,int mnn) 121 { 122 int id1=0,id2=0; 123 for(int i=first[x];i;i=tt[i].next) if(tt[i].y!=ff&&vis[tt[i].y]) 124 { 125 int y=tt[i].y; 126 if(id1==0||mn[id1]>mn[y]) {id2=id1;id1=y;} 127 else if(id2==0||mn[id2]>mn[y]) id2=y; 128 } 129 int w1=mn[id1],w2=mn[id2]; 130 if(id1==0||id2==0) {ans=mymax(ans,mnn);return;} 131 int x1=id[id1],x2=id[id2]; 132 int y1=get_(x1),y2=get_(x2); 133 int now=mymin(get_2(y1,x,INF),get_2(y2,x,INF)); 134 for(int i=first[x];i;i=tt[i].next) if(tt[i].y!=ff&&vis[tt[i].y]) 135 { 136 int y=tt[i].y; 137 if(y==id1||y==id2) continue; 138 now=mymin(now,mn[y]); 139 } 140 now=mymin(now,mnn); 141 ans=mymax(ans,now); 142 vis[x]=0; 143 for(int i=first[x];i;i=tt[i].next) if(tt[i].y!=ff&&vis[tt[i].y]) 144 { 145 int y=tt[i].y,nw; 146 if(y==id1) nw=w2;else nw=w1; 147 rt=0;dfs1(y,0,sm[y]);mn[rt]=INF;get_3(rt,0); 148 dfs2(rt,0,mymin(nw,mnn)); 149 } 150 } 151 152 int main() 153 { 154 int n,m; 155 scanf("%d%d",&n,&m); 156 for(int i=1;i<=m;i++) 157 { 158 int x,y,c; 159 scanf("%d%d%d",&x,&y,&c); 160 ins(x,y,c);ins(y,x,c); 161 } 162 memset(dfn,0,sizeof(dfn)); 163 cnt=0; 164 sl=0;bl=0; 165 ffind(1,0); 166 if(sl!=0) 167 { 168 bl++; 169 while(sl) bcc[sta[sl--]]=bl; 170 } 171 len=0; 172 memset(first,0,sizeof(first)); 173 for(int i=1;i<=2*m;i++) 174 { 175 int x=t[i].x,y=t[i].y; 176 if(bcc[x]==bcc[y]) continue; 177 ins2(bcc[x],bcc[y],t[i].c); 178 } 179 // for(int i=1;i<=n;i++) printf("%d\n",bcc[i]); 180 memset(vis,1,sizeof(vis)); 181 ans=0; 182 rt=0;dfs1(1,0,n);mn[rt]=INF;get_3(rt,0); 183 dfs2(rt,0,INF); 184 if(ans==INF) printf("-1\n"); 185 else printf("%d\n",ans); 186 return 0; 187 }
3、
4332: JSOI2012 分零食
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 103 Solved: 55Description
这里是欢乐的进香河,这里是欢乐的幼儿园。
今天是2月14日,星期二。在这个特殊的日子里,老师带着同学们欢乐地跳着,笑着。校长从幼儿园旁边的小吃店买了大量的零食决定分给同学们。听到这个消息,所有同学都安安静静地排好了队,大家都知道,校长不喜欢调皮的孩子。
同学们依次排成了一列,其中有A位小朋友,有三个共同的欢乐系数O,S和U。如果有一位小朋友得到了x个糖果,那么她的欢乐程度就是f(x)=O*x2+S*x+U。
现在校长开始分糖果了,一共有M个糖果。有些小朋友可能得不到糖果,对于那些得不到糖果的小朋友来说,欢乐程度就是1。如果一位小朋友得不到糖果,那么在她身后的小朋友们也都得不到糖果。(即这一列得不到糖果的小朋友一定是最后的连续若干位)
所有分糖果的方案都是等概率的。现在问题是:期望情况下,所有小朋友的欢乐程度的乘积是多少?呆呆同学很快就有了一个思路,只要知道总的方案个数T和所有方案下欢乐程度乘积的总和S,就可以得到答案Ans=S/T。现在他已经求出来了T的答案,但是S怎么求呢?他就不知道了。你能告诉他么?
因为答案很大,你只需要告诉他S对P取模后的结果。
后记:
虽然大家都知道,即便知道了T,知道了S对P取模后的结果,也没有办法知道期望情况下,所有小朋友欢乐程度的乘积。但是,当呆呆想到这一点的时候,已经彻底绝望了。
Input
第一行有2个整数,分别是M和P。
第二行有一个整数A,第三行有一个整数O。
第四行有一个整数S,第五行有一个整数U。
Output
一个整数S,因为答案可能很大,你只需要输出S 对P取模后的结果。
Sample Input
4 100
4
1
0
0
Sample Output
63
样例说明
函数f(x)=x^2。一共有4份零食,4位同学。如果只有第一个同学得到,欢乐程度为16,若前两位同学得到,欢乐程度的所有可能依次为9,9,16,若有三位同学得到,欢乐程度有4,4,4,最后一种情况,每一个同学都得到了零食,欢乐程度为1。相加后得到S=63。
应上传者要求,此题不公开,如有异议,请提出.
HINT
对于100%的数据,M<=10000,P<=255,A<=108,O<=4,S<=300,U<=100。
Source
我打的O(n^2)以为80分兴冲冲地。。。然而。。。。没分!!!【又打错了小地方。。。
后来发现我的方法可以AC啊!!!时限5s,再次哭瞎。。。
首先容易想到m^3。。
$f[i][j]=f[i-1][j-k]*(a*k*k+b*k+c) $[系数写成$a,b,c$了
其实这个可以优化,因为你会发现有很多重复计算的,【也相当于差分的思想???
先换种形式写:
$f[i][j]=f[i-1][k]*(a*(j-k)*(j-k)+b*(j-k)+c]$
j对比j-1其实右面(j-k)那里多了1,且多了一位可以for到的k
$f[i][j]=f[i][j-1]+f[i-1][k]*(2*a*(j-k-1)+a+b+c)+新的k的一项$
可以继续差分一次
设$g[i][j]=\sum f[i-1][k]*(2*a*(j-k-1)+a+b+c))$
$g[i][j]=g[i][j-1]+f[i-1][k]*2*a+新的k的一项$
这个f[i-1][k]可以直接求前缀和了。
所以是O(n^2)的,但是在bzoj上没有跑过。。 现在过啦!!!!【卡时?
正解fft。。学会了再填坑吧。。
O(n^2):
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 int Mod; 8 int f[2][10010],sm[2][10010]; 9 10 int main() 11 { 12 int m,n,a,b,c; 13 scanf("%d%d%d%d%d%d",&m,&Mod,&n,&a,&b,&c); 14 if(n>m) n=m; 15 memset(f,0,sizeof(f)); 16 memset(sm,0,sizeof(sm)); 17 f[0][0]=sm[0][0]=1; 18 for(int i=1;i<=m;i++) sm[0][i]=sm[0][i-1]+f[0][i]; 19 int ans=0,p=0; 20 for(int j=1;j<=n;j++) 21 { 22 int nw=0,pp=p^1; 23 memset(f[pp],0,sizeof(f[pp])); 24 memset(sm[pp],0,sizeof(sm[pp])); 25 // sm[0]=f[p][0]; 26 // for(int i=1;i<=m;i++) sm[i]=(sm[i-1]+f[p][i])%Mod; 27 for(int i=1;i<=m;i++) 28 { 29 f[pp][i]=f[pp][i-1]; 30 if(i>=3) nw=(nw+sm[p][i-3]*2*a)%Mod; 31 if(i>=2) nw=(nw+f[p][i-2]*(2*a+a+b))%Mod; 32 f[pp][i]=(f[pp][i]+nw+f[p][i-1]*(a+b+c))%Mod; 33 sm[pp][i]=(sm[pp][i-1]+f[pp][i])%Mod; 34 }p^=1; 35 ans=(ans+f[p][m])%Mod; 36 } 37 printf("%d\n",ans); 38 return 0; 39 }
4、
还没看题呢。。。。瞎y了一下。。坑待填。。
2017-04-12 19:56:19