以下代码为了阅读方便,省去以下头文件:

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <math.h>
  4. #include <string.h>
  5. #include <time.h>
  6. #include <stdlib.h>
  7. #include <string>
  8. #include <bitset>
  9. #include <vector>
  10. #include <set>
  11. #include <map>
  12. #include <queue>
  13. #include <algorithm>
  14. #include <sstream>
  15. #include <stack>
  16. #include <iomanip>
  17. using namespace std;
  18. #define pb push_back
  19. #define mp make_pair
  20. typedef pair<int,int> pii;
  21. typedef long long ll;
  22. typedef double ld;
  23. typedef vector<int> vi;
  24. #define fi first
  25. #define se second
  26. #define fe first
  27. #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
  28. #define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);}
  29. #define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);}
  30. #define es(x,e) (int e=fst[x];e;e=nxt[e])
  31. #define esb(x,e,b) (int e=fst[x],b=vb[e];e;e=nxt[e],b=vb[e])

D1 P1

两个长度都为n的字符串,修改不超过k次(一次只能修改任意一串的任意一个字符)使最长公共子串最长。n<=300,k<=350。

枚举最长公共子串在两串中的开头,往后看匹不匹配,不匹配就修改。

  1. #define SZ 666666
  2. int n,k;
  3. char sa[SZ],sb[SZ];
  4. int main()
  5. {
  6. FO(master)
  7. scanf("%d%d%s%s",&n,&k,sa,sb);
  8. int ans=0;
  9. for(int a=0;a<n;a++)
  10. {
  11. for(int b=0;b<n;b++)
  12. {
  13. int cur=0;
  14. for(int l=1;a+l<=n&&b+l<=n;l++)
  15. {
  16. cur+=(sa[l+a-1]!=sb[l+b-1]);
  17. if(cur>k) break;
  18. ans=max(ans,l);
  19. }
  20. }
  21. }
  22. printf("%d\n",ans);
  23. }

D1 P2

给出一个n个点的图的邻接矩阵,求有多少条简单路径恰好经过了4个点。n<=1500。

我们枚举一条边作为简单路径中间的一条边,那么对答案的贡献就是(d1-1)*(d2-1)*2类似这样。

这时候我们发现三元环好像会被计算若干次,扣掉就行了。三元环的个数只要枚举一条边,两个端点的邻接矩阵and在一起看一下有多少个1就行。bitset一波。

  1. #define SZ 666666
  2. int n;
  3. ll cc[SZ];
  4. char rp[1505][1505];
  5. bitset<1503> bs[1505];
  6. int main()
  7. {
  8. FO(tour)
  9. scanf("%d\n",&n);
  10. for(int i=1;i<=n;i++) gets(rp[i]+1);
  11. for(int i=1;i<=n;i++)
  12. {
  13. for(int j=1;j<=n;j++)
  14. {
  15. cc[j]+=(rp[i][j]=='1');
  16. bs[i][j]=rp[i][j]-'0';
  17. }
  18. }
  19. ll ans=0,cyc=0;
  20. for(int i=1;i<=n;i++)
  21. {
  22. for(int j=i+1;j<=n;j++)
  23. {
  24. if(rp[i][j]!='1') continue;
  25. ans+=(cc[i]-1)*(cc[j]-1)*2;
  26. }
  27. }
  28. for(int i=1;i<=n;i++)
  29. {
  30. for(int j=i+1;j<=n;j++)
  31. if(rp[i][j]=='1') cyc+=(bs[i]&bs[j]).count();
  32. }
  33. cout<<ans-cyc*2<<"\n";
  34. }

D1 P3

有n个点,编号为1~n,开始有m条单向边。每个点有一个编码val,如果$val_i~and~val_j=val_j$,那么i->j也有一条单向边。边权都为1,求1号点到每一个点的距离。n<=20W,m<=30W,1<=val<2^20。

我们考虑把每个val建一个点,假设对于一个val的位置为val+r,i->val[i]+r连一条权值为1的边,val[i]+r->i连一条权值为0的边,那么我们只要让val里面连的那些边边权为0就行了。

val里面连边暴力连显然比较蠢,我们只连二进制相差一位的val,这样传递一下就相当于连了所有变了。

至于边权为0和1的最短路怎么跑...2^20个点,spfa显然过不去。有一种技巧是边权为0的扩展完塞到队头,边权为1的塞到队尾,这样bfs就可以了。

  1. #define SZ 11500003
  2. int N,n,m,vs[233333];
  3. int M=0,fst[1281909],vb[SZ],nxt[SZ];
  4. bool vc[SZ];
  5. void ad_de(int a,int b,int c)
  6. {++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}
  7. int r=0,lim=1<<20;
  8. int dist[1281909];
  9. #define P 2097151
  10. int qs[P+3];
  11. void spfa()
  12. {
  13. memset(dist,127/3,sizeof(dist));
  14. dist[1]=0;
  15. int h=0,t=0; qs[t++]=1;
  16. while(h^t)
  17. {
  18. int x=qs[h++]; h&=P;
  19. if(dist[x]>=dist[0]) continue;
  20. for es(x,e)
  21. {
  22. int b=vb[e],c=vc[e];
  23. if(dist[b]<=dist[x]+c) continue;
  24. dist[b]=dist[x]+c;
  25. if(c) qs[t++]=b, t&=P;
  26. else qs[h=(h-1)&P]=b;
  27. }
  28. }
  29. }
  30. char ch,B[1<<15],*S=B,*T=B;
  31. #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
  32. #define isd(c) (c>='0'&&c<='9')
  33. int aa,bb;int F(){
  34. while(ch=getc(),!isd(ch)&&ch!='-');ch=='-'?aa=bb=0:(aa=ch-'0',bb=1);
  35. while(ch=getc(),isd(ch))aa=aa*10+ch-'0';return bb?aa:-aa;
  36. }
  37. #define gi F()
  38. #define BUFSIZE 300000
  39. namespace fob {char b[BUFSIZE]={},*f=b,*g=b+BUFSIZE-2;}
  40. #define pob (fwrite(fob::b,sizeof(char),fob::f-fob::b,stdout),fob::f=fob::b,0)
  41. #define pc(x) (*(fob::f++)=(x),(fob::f==fob::g)?pob:0)
  42. struct foce {~foce() {pob; fflush(stdout);}} _foce;
  43. namespace ib {char b[100];}
  44. inline void pint(int x)
  45. {
  46. if(x==0) {pc(48); return;}
  47. if(x<0) {pc('-'); x=-x;}
  48. char *s=ib::b;
  49. while(x) *(++s)=x%10, x/=10;
  50. while(s!=ib::b) pc((*(s--))+48);
  51. }
  52. int main()
  53. {
  54. FO(walk)
  55. n=N=gi; m=gi;
  56. for(int i=1;i<=n;i++) vs[i]=gi;
  57. for(int i=1;i<=m;i++)
  58. {
  59. int a=gi,b=gi;
  60. ad_de(a,b,1);
  61. }
  62. r=n+1; n+=lim;
  63. for(int i=1;i<=N;i++) ad_de(i,vs[i]+r,1);
  64. for(int i=1;i<=N;i++) ad_de(vs[i]+r,i,0);
  65. int m1=M;
  66. for(int j=0;(1<<j)<lim;j++)
  67. {
  68. for(int i=0;i<lim;i++)
  69. {
  70. int nx=i|(1<<j);
  71. if(i==nx||nx>=lim) continue;
  72. ad_de(nx+r,i+r,0);
  73. }
  74. }
  75. spfa();
  76. for(int i=1;i<=N;i++)
  77. {
  78. if(dist[i]>=dist[0]) dist[i]=-1;
  79. pint(dist[i]); pc(10);
  80. }
  81. }

D2 T1

给定m个不同正整数a1~am,对于0~m的每一个k,求[1,n]中有多少个数是a中恰好k个数的倍数。m<=200,1<=n,a<=10^9。

枚举每个数的约数即可,下面这个代码写的比较智障。

  1. vector<pii> fj(int x)
  2. {
  3. vector<pii> vec;
  4. for(int i=2;i*i<=x;i++)
  5. {
  6. if(x%i) continue;
  7. pii cur=pii(i,0);
  8. while(x%i==0) ++cur.se, x/=i;
  9. vec.pb(cur);
  10. }
  11. if(x>1) vec.pb(pii(x,1));
  12. return vec;
  13. }
  14. vector<pii> pp;
  15. vi yy;
  16. void dfs(int dep=0,int c1=1)
  17. {
  18. if(dep==pp.size())
  19. {
  20. yy.push_back(c1);
  21. return;
  22. }
  23. int a=pp[dep].fi,b=pp[dep].se;
  24. for(int j=0;j<=b;j++)
  25. {
  26. dfs(dep+1,c1);
  27. c1*=a;
  28. }
  29. }
  30. vi yss(int x)
  31. {
  32. yy.clear();
  33. pp=fj(x);
  34. dfs();
  35. return yy;
  36. }
  37. int n,m,a[SZ];
  38. set<int> si;
  39. int cc[SZ];
  40. int cnt(int s)
  41. {
  42. int ans=0;
  43. for(int i=1;i<=m;i++) ans+=(a[i]%s==0);
  44. return ans;
  45. }
  46. int main()
  47. {
  48. FO(div)
  49. scanf("%d%d",&n,&m);
  50. for(int i=1;i<=m;i++) scanf("%d",a+i);
  51. for(int i=1;i<=m;i++)
  52. {
  53. vi t=yss(a[i]);
  54. for(int j=0;j<t.size();j++) si.insert(t[j]);
  55. }
  56. for(set<int>::iterator p=si.begin();p!=si.end();++p)
  57. {
  58. int g=*p;
  59. if(g>n) continue;
  60. ++cc[cnt(g)];
  61. }
  62. int sum=n;
  63. for(int i=0;i<=m;i++) sum-=cc[i];
  64. cc[0]+=sum;
  65. for(int i=0;i<=m;i++) printf("%d\n",cc[i]);
  66. }

D2 T2

有n个商店,每个商店卖一个物品,一个物品有价格、价值,商店会在某一时间开张。

要进行m次购物,每次购物有一个预算,在某个时间开始,求每次的最大价值,购买之间独立。

n<=300,m<=10W,价格、预算<=10^9,价值、时间<=300。

询问离线后按时间排序。既然价值这么小,我们就用dp[i]表示达到i这么多的价值最少的价格,询问时二分。

  1. #define SZ 666666
  2. int n,m;
  3. struct shop {int c,v,t;}cs[SZ];
  4. struct plan {int t,m,id,ans;}ps[SZ];
  5. bool operator < (shop a,shop b)
  6. {return a.t<b.t;}
  7. bool operator < (plan a,plan b)
  8. {return a.t<b.t;}
  9. bool cid(plan a,plan b)
  10. {return a.id<b.id;}
  11. int W=90000;
  12. ll rp[99999];
  13. int cur=1;
  14. void pt(ll t)
  15. {
  16. while(cur<=n&&ps[cur].t<t)
  17. {
  18. int l=0,r=W;
  19. while(l<r)
  20. {
  21. int m=(l+r+1)>>1;
  22. if(rp[m]<=ps[cur].m) l=m; else r=m-1;
  23. }
  24. ps[cur++].ans=l;
  25. }
  26. }
  27. int main()
  28. {
  29. FO(market)
  30. scanf("%d%d",&n,&m);
  31. for(int i=1;i<=n;i++)
  32. scanf("%d%d%d",&cs[i].c,&cs[i].v,&cs[i].t);
  33. for(int i=1;i<=m;i++)
  34. scanf("%d%d",&ps[i].t,&ps[i].m), ps[i].id=i;
  35. sort(ps+1,ps+1+m);
  36. sort(cs+1,cs+1+n);
  37. memset(rp,127/3,sizeof(rp)); rp[0]=0;
  38. for(int i=1;i<=n;i++)
  39. {
  40. pt(cs[i].t);
  41. for(int j=W;j>=cs[i].v;j--)
  42. rp[j]=min(rp[j],cs[i].c+rp[j-cs[i].v]);
  43. }
  44. pt(1e9+3);
  45. sort(ps+1,ps+1+m,cid);
  46. for(int i=1;i<=m;i++) printf("%d\n",ps[i].ans);
  47. }

D2 T3

有一棵n个点的树,每条边i有一个限制区间[li,ri]表示速度在[li,ri]才能通过这条边。现在给出m个询问,每次给出一个速度求最长链。n,m<=70000,1<=li<=ri<=n。

首先我们知道我们是可以加边和维护一个森林的直径的。并查集,合并两个联通块时新直径只可能从6个点产生:原来两条直径的端点和接在一起的那条边。此外,我们也可以按照加边的顺序倒着撤销,只要并查集是按秩合并的就可以。

接下来我们考虑对于速度建出一棵线段树,然后那么一个限制区间就可以下放到线段树上的若干个节点,而一个询问针对的是一个叶子节点,满足条件的是这个叶子节点到线段树根上的这些边。那我们在线段树上dfs,进入一个节点的时候加上这个节点的边,出去的时候撤销这些边,这样就行了。

以下的代码没有在bzoj评测机上测过,(很有)可能会被卡常/爆内存。

  1. #define SZ 200003
  2. ll MOD=998244353;
  3. Edg
  4. #define P 19
  5. typedef pair<int,int> pii;
  6. int n,fa[SZ],dep[SZ];
  7. int cc=0,app[SZ],bs[SZ],cx[SZ],c2=0;
  8. pii pp[SZ],minn[SZ][P];
  9. void dfs(int x)
  10. {
  11. ++cc; app[x]=cc; pp[cc]=pii(dep[x],x); cx[++c2]=x;
  12. for(int e=fst[x];e;e=nxt[e])
  13. {
  14. int b=vb[e]; if(b==fa[x]) continue;
  15. fa[b]=x; dep[b]=dep[x]+1;
  16. dfs(b); pp[++cc]=pii(dep[x],x);
  17. }
  18. }
  19. void build()
  20. {
  21. for(int i=1;i<=cc;i++) minn[i][0]=pp[i];
  22. for(int i=1;i<=cc;i++)
  23. {
  24. int g=0;
  25. while((1<<g)<=i) ++g;
  26. bs[i]=g-1;
  27. }
  28. for(int p=1;p<P;p++)
  29. {
  30. for(int i=1;i<=cc;i++)
  31. {
  32. if(i+(1<<p)-1>cc) break;
  33. minn[i][p]=min(minn[i][p-1],minn[i+(1<<(p-1))][p-1]);
  34. }
  35. }
  36. }
  37. int lca(int a,int b)
  38. {
  39. a=app[a]; b=app[b];
  40. if(a>b) swap(a,b);
  41. int l2=bs[b-a+1];
  42. return min(minn[a][l2],minn[b-(1<<l2)+1][l2]).second;
  43. }
  44. int dis(int a,int b)
  45. {
  46. int l=lca(a,b);
  47. return dep[a]+dep[b]-dep[l]*2;
  48. }
  49. pii mg(pii a,int b)
  50. {
  51. int s[3]={a.fi,a.se,b};
  52. pii aa; int ans=-1;
  53. for(int i=0;i<3;i++)
  54. {
  55. for(int j=i+1;j<3;j++)
  56. {
  57. int d=dis(s[i],s[j]);
  58. if(d>ans) ans=d, aa=pii(s[i],s[j]);
  59. }
  60. }
  61. return aa;
  62. }
  63. //a,b为直径,c为衔接处
  64. pii mg(pii a,pii b,pii c)
  65. {
  66. pii aa=a; int ans=dis(a.fi,a.se);
  67. {
  68. int tmp=dis(b.fi,b.se);
  69. if(tmp>ans) ans=tmp, aa=b;
  70. }
  71. int as[3]={a.fi,a.se,c.fi},bs[3]={b.fi,b.se,c.se};
  72. for(int i=0;i<3;i++)
  73. {
  74. for(int j=0;j<3;j++)
  75. {
  76. int d=dis(as[i],bs[j]);
  77. if(d>ans) ans=d, aa=pii(as[i],bs[j]);
  78. }
  79. }
  80. return aa;
  81. }
  82. int m;
  83. struct Tuple {int f; pii z;};
  84. int ans=0,ff[SZ];
  85. pii zj[SZ];
  86. int gf(int x)
  87. {
  88. return (ff[x]>0)?gf(ff[x]):x;
  89. }
  90. struct Msg
  91. {
  92. int ga,gb,fa,fb;
  93. pii pa,pb;
  94. Msg() {ga=gb=0;}
  95. Msg(int a,int b,int c,int d,pii x,pii y) {ga=a; gb=b; fa=c; fb=d; pa=x; pb=y;}
  96. };
  97. //use the return value to reverse!
  98. Msg uni(int u,int v)
  99. {
  100. int ga=gf(u),gb=gf(v);
  101. if(ga==gb) return Msg();
  102. if(ff[ga]>ff[gb]) swap(ga,gb);
  103. Msg rt=Msg(ga,gb,ff[ga],ff[gb],zj[ga],zj[gb]);
  104. pii tmp=mg(zj[ga],zj[gb],pii(u,v));
  105. zj[ga]=tmp; ff[ga]+=ff[gb]; ff[gb]=ga;
  106. return rt;
  107. }
  108. void rev(Msg p)
  109. {
  110. if(!p.ga) return;
  111. ff[p.ga]=p.fa; ff[p.gb]=p.fb;
  112. zj[p.ga]=p.pa; zj[p.gb]=p.pb;
  113. }
  114. #define ST 8888888
  115. struct edg {int u,v,l,r;}es[SZ];
  116. namespace seg
  117. {
  118. const int M=131072;
  119. int nx[ST],fs[M+M+3],bb[ST],C=0;
  120. Msg tmp[ST];
  121. void split(int l,int r,int g)
  122. {
  123. for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1)
  124. {
  125. if(~l&1)
  126. {++C; bb[C]=g; nx[C]=fs[l^1]; fs[l^1]=C;}
  127. if(r&1)
  128. {++C; bb[C]=g; nx[C]=fs[r^1]; fs[r^1]=C;}
  129. }
  130. }
  131. int cm[M+M+3];
  132. int tat[ST];
  133. void dfs(int x,int zjj=0)
  134. {
  135. for(int e=fs[x];e;e=nx[e])
  136. {
  137. int b=bb[e];
  138. tmp[e]=uni(es[b].u,es[b].v);
  139. int a=tmp[e].ga;
  140. if(!a) continue;
  141. zjj=max(zjj,dis(zj[a].fi,zj[a].se));
  142. }
  143. if(x>M) cm[x]=zjj;
  144. else
  145. {
  146. dfs(x*2,zjj);
  147. dfs(x*2+1,zjj);
  148. }
  149. int tn=0;
  150. for(int e=fs[x];e;e=nx[e]) tat[++tn]=e;
  151. while(tn) rev(tmp[tat[tn--]]);
  152. }
  153. }
  154. #define BUFSIZE 300000
  155. char ch,B[1<<15],*S=B,*T=B;
  156. #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
  157. #define isd(c) (c>='0'&&c<='9')
  158. int aa,bb;int F(){
  159. while(ch=getc(),!isd(ch)&&ch!='-');ch=='-'?aa=bb=0:(aa=ch-'0',bb=1);
  160. while(ch=getc(),isd(ch))aa=aa*10+ch-'0';return bb?aa:-aa;
  161. }
  162. #define gi F()
  163. namespace fob {char b[BUFSIZE]={},*f=b,*g=b+BUFSIZE-2;}
  164. #define pob (fwrite(fob::b,sizeof(char),fob::f-fob::b,stdout),fob::f=fob::b,0)
  165. #define pc(x) (*(fob::f++)=(x),(fob::f==fob::g)?pob:0)
  166. struct foce {~foce() {pob; fflush(stdout);}} _foce;
  167. namespace ib {char b[100];}
  168. inline void pint(int x)
  169. {
  170. if(x==0) {pc(48); return;}
  171. if(x<0) {pc('-'); x=-x;}
  172. char *s=ib::b;
  173. while(x) *(++s)=x%10, x/=10;
  174. while(s!=ib::b) pc((*(s--))+48);
  175. }
  176. int main()
  177. {
  178. FO(speed)
  179. n=gi, m=gi;
  180. for(int i=1;i<n;i++)
  181. {
  182. es[i].u=gi, es[i].v=gi, es[i].l=gi, es[i].r=gi;
  183. adde(es[i].u,es[i].v);
  184. }
  185. for(int i=1;i<=n;i++) ff[i]=-1, zj[i]=pii(i,i);
  186. dfs(1); build();
  187. for(int i=1;i<n;i++)
  188. seg::split(es[i].l,es[i].r,i);
  189. seg::dfs(1);
  190. for(int i=1;i<=m;i++)
  191. {
  192. int q=gi;
  193. pint(seg::cm[q+seg::M]); pc(10);
  194. }
  195. }

D3 T1

一个长度为n的序列,计算每个连续子序列(子段)的平均数,求第k小的平均数,n<=10W。

二分答案,那么我们要知道平均值<s的子段有几个,我们把所有数都减去s,就是要求和<0的子段个数,即前缀和逆序对个数。

由于懒得离散,写的归并

  1. #define SZ 666666
  2. int n,aa[SZ];
  3. ll k,nx=0;
  4. ld rp[SZ],tmp[SZ];
  5. void fz(int l,int r)
  6. {
  7. if(l==r) return;
  8. int tn=0,m=(l+r)>>1;
  9. fz(l,m); fz(m+1,r);
  10. int x=l;
  11. for(int i=m+1;i<=r;i++)
  12. {
  13. while(x<=m&&rp[x]<rp[i]) tmp[++tn]=rp[x++];
  14. nx+=m-x+1; tmp[++tn]=rp[i];
  15. }
  16. while(x<=m) tmp[++tn]=rp[x++];
  17. tn=0;
  18. for(int i=l;i<=r;i++) rp[i]=tmp[++tn];
  19. }
  20. //平均值<=s的有几个?
  21. ll cnt(ld s)
  22. {
  23. rp[0]=0;
  24. for(int i=1;i<=n;i++) rp[i]=rp[i-1]+aa[i]-s;
  25. nx=0; fz(0,n); return nx;
  26. }
  27. int main()
  28. {
  29. FO(ave)
  30. scanf("%d%I64d",&n,&k);
  31. for(int i=1;i<=n;i++) scanf("%d",aa+i);
  32. ld l=0,r=1e9+3;
  33. for(int i=1;i<=80;i++)
  34. {
  35. ld m=(l+r)/2;
  36. if(cnt(m)<k) l=m; else r=m;
  37. }
  38. printf("%.4lf\n",l);
  39. }

D3 T2

有一个n*m的网格,要用p种颜色涂色,使每相邻两列都出现了至少q种颜色,求方案数mod 998244353。n,p,q<=100且q<=p,m<=10^9。

我们用dp[a][b]表示前a列,第a列用了b种颜色的方案数,然后我们考虑枚举下一列用了x种新颜色,y种旧颜色,那么dp[a+1][x+y]+=C(b,x)*C(p-b,y)*pal(n,a+b),其中pal(a,b)表示用恰好b种颜色染a个球的方案数。

注意到这个a是打酱油的,我们拿去矩阵快速幂优化一下。

至于这个pal怎么算,我们枚举在c种颜色中使用了多少种颜色,容斥一发即可。感觉这个东西应该有更优美的算法(这样硬算预处理是立方的),如果有知道的老司机求回答一下:http://stackoverflow.com/questions/39955981/how-to-calculate-the-ways-to-paint-n-different-balls-with-exact-c-different-colo

  1. #define SZ 666666
  2. ll MOD=998244353;
  3. ll C[233][233],fac[233],P[233][233];
  4. ll pal[233][233];
  5. ll pp[233][233];
  6. int n,m,p,q;
  7. ll qp(ll a,ll b)
  8. {
  9. a%=MOD; ll ans=1;
  10. while(b)
  11. {
  12. if(b&1) ans=ans*a%MOD;
  13. a=a*a%MOD; b>>=1;
  14. }
  15. return ans;
  16. }
  17. //paint a with b colors
  18. ll sel(int a,int b)
  19. {
  20. ll ans=0;
  21. for(int j=1;j<=b;j++)
  22. {
  23. if(j%2==b%2) ans+=pp[j][a]*C[b][j]%MOD;
  24. else ans-=pp[j][a]*C[b][j]%MOD;
  25. ans%=MOD;
  26. }
  27. return ans;
  28. }
  29. int N;
  30. struct mat
  31. {
  32. ll rp[110][110];
  33. ll* operator [] (int p) {return rp[p];}
  34. void clr() {memset(rp,0,sizeof(rp));}
  35. };
  36. mat operator * (mat a,mat b)
  37. {
  38. mat ans; ans.clr();
  39. for(int i=0;i<N;i++)
  40. {
  41. for(int j=0;j<N;j++)
  42. {
  43. ll g=0;
  44. for(int k=0;k<N;k++)
  45. g=(g+a[i][k]*b[k][j]%MOD)%MOD;
  46. ans[i][j]=g;
  47. }
  48. }
  49. return ans;
  50. }
  51. mat dw()
  52. {
  53. mat ans; ans.clr();
  54. for(int i=0;i<N;i++) ans[i][i]=1;
  55. return ans;
  56. }
  57. mat zy;
  58. mat qp(mat x,int g)
  59. {
  60. mat cur=dw();
  61. while(g)
  62. {
  63. if(g&1) cur=cur*x;
  64. x=x*x; g>>=1;
  65. }
  66. return cur;
  67. }
  68. int main()
  69. {
  70. FO(color)
  71. fac[0]=1;
  72. for(int i=1;i<=200;i++) fac[i]=fac[i-1]*i%MOD;
  73. for(int i=0;i<=200;i++)
  74. {
  75. C[i][0]=1;
  76. for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
  77. for(int j=0;j<=i;j++) P[i][j]=C[i][j]*fac[j]%MOD;
  78. }
  79. for(int i=0;i<=200;i++)
  80. {
  81. pp[i][0]=1;
  82. for(int j=1;j<=200;j++) pp[i][j]=pp[i][j-1]*i%MOD;
  83. }
  84. for(int i=0;i<=200;i++)
  85. {
  86. for(int j=1;j<=200;j++) pal[i][j]=sel(i,j);
  87. }
  88. cin>>n>>m>>p>>q;
  89. N=p+1;
  90. for(int j=0;j<=p;j++)
  91. {
  92. for(int a=0;a<=j;a++)
  93. {
  94. for(int b=0;b<=p-j;b++)
  95. {
  96. if(a+b==0) continue;
  97. if(j+b>=q);else continue;
  98. ll &s=zy[j][a+b];
  99. ll px=C[j][a]*C[p-j][b]%MOD*pal[n][a+b]%MOD;
  100. s=(s+px)%MOD;
  101. }
  102. }
  103. }
  104. mat ss=qp(zy,m);
  105. ll ans=0;
  106. for(int i=0;i<N;i++) ans+=ss[p][i], ans%=MOD;
  107. cout<<(ans%MOD+MOD)%MOD<<"\n";
  108. }

D3 T3

有一个长度为n的序列和m个询问,每个询问都是l r x的形式,表示询问l~r位置有多少个数>=x。现在有q次修改,每次要改变一个位置上的数。要求在修改前和每次修改后输出每个询问结果的和,修改强制在线(xor lastans)。

我们考虑一个位置上的数,例如a[s]=g,会对l<=s<=r且g>=s的询问有1的贡献,那么我们只要能数这些询问就可以了,差分完主席树就行。

  1. #define enc
  2. #define SZ 666666
  3. #define S2 6666666
  4. int ch[S2][2],rot[SZ],sum[S2],an=0;
  5. void ins(int r1,int& r2,int l,int r,int p,int q)
  6. {
  7. if(!r2) r2=++an;
  8. sum[r2]=sum[r1]+q;
  9. if(l==r) return;
  10. int mid=l+r>>1;
  11. if(p<=mid) ins(ch[r1][0],ch[r2][0],l,mid,p,q), ch[r2][1]=ch[r1][1];
  12. else ins(ch[r1][1],ch[r2][1],mid+1,r,p,q), ch[r2][0]=ch[r1][0];
  13. }
  14. int query(int r2,int l,int r,int p)
  15. {
  16. if(l>p) return 0;
  17. if(r<=p) return sum[r2];
  18. int mid=l+r>>1,ans=0;
  19. ans+=query(ch[r2][0],l,mid,min(p,mid));
  20. if(p>mid) ans+=query(ch[r2][1],mid+1,r,p);
  21. return ans;
  22. }
  23. int n,m,q,a[SZ];
  24. int ls[SZ],rs[SZ],xs[SZ];
  25. int query(int g,int s)
  26. {return query(rot[g],0,n,s);}
  27. ll aa=0;
  28. struct data
  29. {
  30. int r,x,g;
  31. data() {}
  32. data(int a,int b,int c) {r=a; x=b; g=c;}
  33. };
  34. bool operator < (data a,data b)
  35. {return a.r<b.r;}
  36. data ds[SZ];
  37. int dn=0;
  38. namespace FFF
  39. {
  40. char ch,B[1<<15],*S=B,*T=B;
  41. #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
  42. #define isd(c) (c>='0'&&c<='9')
  43. ll aa,bb;
  44. ll F(){
  45. while(ch=getc(),!isd(ch)&&ch!='-');ch=='-'?aa=bb=0:(aa=ch-'0',bb=1);
  46. while(ch=getc(),isd(ch))aa=aa*10+ch-'0';return bb?aa:-aa;
  47. }
  48. }
  49. #define gl FFF::F()
  50. int main()
  51. {
  52. FO(seq)
  53. n=gl, m=gl, q=gl;
  54. //scanf("%d%d%d",&n,&m,&q);
  55. for(int i=1;i<=n;i++) a[i]=gl;//scanf("%d",a+i);
  56. for(int i=1;i<=m;i++) ls[i]=gl, rs[i]=gl, xs[i]=gl;
  57. //scanf("%d%d%d",ls+i,rs+i,xs+i);
  58. for(int i=1;i<=m;i++)
  59. {
  60. ds[++dn]=data(ls[i],xs[i],1);
  61. ds[++dn]=data(rs[i]+1,xs[i],-1);
  62. }
  63. sort(ds+1,ds+1+dn);
  64. int cur=0,cp=1;
  65. for(int i=0;i<=n+1;i++)
  66. {
  67. int p=0;
  68. while(cp<=dn&&ds[cp].r==i)
  69. {
  70. p=0;
  71. ins(cur,p,0,n,ds[cp].x,ds[cp].g);
  72. //cout<<i<<" "<<ds[cp].x<<","<<ds[cp].g<<"\n";
  73. ++cp; cur=p;
  74. }
  75. rot[i]=cur;
  76. }
  77. for(int i=1;i<=n;i++) aa+=query(i,a[i]);
  78. ll lans=aa; printf("%I64d\n",lans);
  79. while(q--)
  80. {
  81. ll x=gl,y=gl;
  82. //scanf("%I64d%I64d",&x,&y);
  83. #ifdef enc
  84. x^=lans; y^=lans;
  85. #else
  86. //debug only
  87. #warning Encrypt?
  88. #endif
  89. aa-=query(x,a[x]);
  90. a[x]=y;
  91. aa+=query(x,a[x]);
  92. printf("%I64d\n",aa);
  93. lans=aa;
  94. }
  95. }

D4 T1

开始有a个红色,b个黄色,c个蓝色,要求至少x个红色,y个黄色,z个蓝色,每次可以把任何两个同种颜色转化为一个另一种颜色,问是否可行。多组询问,T<=100,0<=a,b,c,x,y,z<=1000000。

如果你不想动脑子,你可以每次把最多的分给最少的,这样暴力就行了。

如果你打算动脑子,我们考虑如果a比x大就有了(a-x)/2的空余,否则就有a-x的需求,只要判需求<=空余就行了。

  1. int tar[3],x[3];
  2. int main()
  3. {
  4. FO(osiris)
  5. int T; scanf("%d",&T);
  6. while(T--)
  7. {
  8. scanf("%d%d%d%d%d%d",x,x+1,x+2,tar,tar+1,tar+2);
  9. while(x[0]<tar[0]||x[1]<tar[1]||x[2]<tar[2])
  10. {
  11. int need=0,ok=-1;
  12. if(x[1]<tar[1]) need=1;
  13. if(x[2]<tar[2]) need=2;
  14. if(x[0]-2>=tar[0]) ok=0;
  15. if(x[1]-2>=tar[1]) ok=1;
  16. if(x[2]-2>=tar[2]) ok=2;
  17. if(ok==-1) break;
  18. x[ok]-=2; x[need]++;
  19. }
  20. bool yy=1;
  21. for(int i=0;i<3;i++) yy&=(x[i]>=tar[i]);
  22. if(yy) puts("YES"); else puts("NO");
  23. }
  24. }

D4 T2

给一个n个点m条边的有向图,求有多少个子图(即边集)是无环的,对1e9+7取模。n<=17。

不是很懂题解,待填坑。

D4 T3

给定n,求1<=a,b<=n且lcm(a,b)>n的(a,b)对数mod 1e9+7。

首先我们不妨把求lcm(a,b)>n改为求lcm(a,b)<=n,然后枚举gcd。

然后设,这个不妨设a<=b然后枚举b来算,就可以做到O(sqrt(k))。

那么我们枚举一下gcd,扣掉gcd不为1的就行了:

然后老套路,小的情况线筛预处理。那么怎么线筛?

我们考察f(n)-f(n-1),这部分一定是乘积为n且互质的两个数...那就是2^(n的不同因子个数啊),因为每个因子只能由一个数取光。

这样我们对于<=n^(2/3)的线筛,用老套路积分可以得到复杂度为O(n^(2/3))。

  1. #define SZ 2333333
  2. #define M 2000000
  3. typedef long long ll;
  4. ll p2[SZ];
  5. bool np[SZ];
  6. int ps[SZ],pn=0;
  7. ll f[SZ];
  8. ll MOD=1000000007;
  9. void shai()
  10. {
  11. np[1]=1; p2[1]=1;
  12. for(int i=2;i<=M;i++)
  13. {
  14. if(!np[i]) {ps[++pn]=i; p2[i]=2;}
  15. for(int j=1;j<=pn&&i*ps[j]<=M;j++)
  16. {
  17. int nx=i*ps[j]; np[nx]=1;
  18. if(i%ps[j]) p2[nx]=p2[i]*2;
  19. else {p2[nx]=p2[i]; break;}
  20. }
  21. }
  22. for(int i=1;i<=M;i++) f[i]=(f[i-1]+p2[i])%MOD;
  23. }
  24. ll gs(ll x)
  25. {
  26. ll ans=0;
  27. for(ll i=1;i*i<=x;i++) ans+=(x/i-i)*2+1;
  28. return ans%MOD;
  29. }
  30. ll gf(ll x)
  31. {
  32. if(x<=M) return f[x];
  33. ll s=gs(x);
  34. for(ll t=2;t*t<=x;t++) s-=gf(x/t/t);
  35. return s%MOD;
  36. }
  37. int main()
  38. {
  39. shai();
  40. ll n,ans=0; cin>>n;
  41. for(ll s=1;s<=n;s=n/(n/s)+1)
  42. {
  43. ll ls=n/(n/s);
  44. ans+=gf(n/s)*(ls-s+1)%MOD;
  45. ans%=MOD;
  46. }
  47. ll aa=(n%MOD)*(n%MOD)%MOD-ans;
  48. aa=(aa%MOD+MOD)%MOD;
  49. cout<<aa<<"\n";
  50. }

今天先施工到这。

UPD:辣鸡zzq noip后弃坑了,有心情估计不会再更新这篇文章不然我哪有心情更新新博客QAQ

noip2016十连测题解的更多相关文章

  1. noip2016十连测round3

    A:平均数 题意:有一天,小 A 得到了一个长度为 n 的序列. 他把这个序列的所有连续子序列都列了出来,并对每一个子序列都求了其平均值,然后他把这些平均值写在纸上,并对它们进行排序,最后他报出了第 ...

  2. Problem C: [noip2016十连测第五场]travel (构造+贪心)

    题面 https://www.lydsy.com/JudgeOnline/upload/201610/statements(1).pdf 题解 好神仙的贪心-- 首先无解的情况很容易判断,就是\(l= ...

  3. noip2016十连测round2

    A: Divisors 题意:给定 m 个不同的正整数 a 1 ,a 2 ,...,a m ,请对 0 到 m 每一个 k 计算,在区间 [1,n] 里有多少正整数 是 a 中恰好 k 个数的约数. ...

  4. noip2016十连测round1

    A:String Master 题目:所谓最长公共子串,比如串 A:"abcde",串 B:"jcdkl",则它们的最长公共子串为串 "cd" ...

  5. NOIp2016 十连测 round1

    Claris大爷出的一套模拟题.问别人要到了一份题,加深了自己NOIp要滚粗的感觉. Matser zzDP题,我只能说我第一遍写的时候还写崩了QAQ. //master //by Cydiater ...

  6. bzoj 5216 [Lydsy2017省队十连测]公路建设 线段树维护 最小生成树

    [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 93  Solved: 53[Submit][Status][ ...

  7. ZROI2019 提高十连测

    额 掰手指头一数 特么又是第三年十连测了= = 2017一场没打 那时候好像一场比赛也就100人左右 2018前几场还都好好补了 后来开始放飞自我了 这时候一场有150人还多了 2019想让今年的No ...

  8. Lydsy2017省队十连测

    5215: [Lydsy2017省队十连测]商店购物 可能FFT学傻了,第一反应是前面300*300背包,后面FFT... 实际上前面背包,后面组合数即可.只是这是一道卡常题,需要注意常数.. //A ...

  9. bzoj 5216: [Lydsy2017省队十连测]公路建设

    5216: [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 66  Solved: 37[Submit][St ...

随机推荐

  1. DropDownList 下拉框选择改变,促发事件和防全局刷新(记录)

    代码: <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:Script ...

  2. 【基于WinForm+Access局域网共享数据库的项目总结】之篇二:WinForm开发扇形图统计和Excel数据导出

    篇一:WinForm开发总体概述与技术实现 篇二:WinForm开发扇形图统计和Excel数据导出 篇三:Access远程连接数据库和窗体打包部署 [小记]:最近基于WinForm+Access数据库 ...

  3. Java豆瓣电影爬虫——抓取电影详情和电影短评数据

    一直想做个这样的爬虫:定制自己的种子,爬取想要的数据,做点力所能及的小分析.正好,这段时间宝宝出生,一边陪宝宝和宝妈,一边把自己做的这个豆瓣电影爬虫的数据采集部分跑起来.现在做一个概要的介绍和演示. ...

  4. 现代3D图形编程学习-基础简介(1) (译)

    本书系列 现代3D图形编程学习 基础简介 并不像本书的其他章节,这章内容没有相关的源代码或是项目.本章,我们将讨论向量,图形渲染理论,以及OpenGL. 向量 在阅读这本书的时候,你需要熟悉代数和几何 ...

  5. FFmpeg学习5:多线程播放视音频

    在前面的学习中,视频和音频的播放是分开进行的.这主要是为了学习的方便,经过一段时间的学习,对FFmpeg的也有了一定的了解,本文就介绍了 如何使用多线程同时播放音频和视频(未实现同步),并对前面的学习 ...

  6. error RC1015: cannot open include file 'afxres.h' 解决办法

    在为WindowsPhone8程序添加本地化的过程中遇到这个问题: 问题原因就是afxres.h文件缺失,下载它,放到VS安装目录下的VS\include目录下就可以了(选择目录的时候注意对应对版本) ...

  7. WPF入门:XAML

    XAML是WPF技术中专门用于设计UI的语言 XAML优点最大的优点是将UI与逻辑代码剥离 创建第一个WPF应用程序 VS默认生成的WPF项目解决方案 Properties:里面主要包含了程序用到的一 ...

  8. 学习Redis你必须了解的数据结构——HashMap实现

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接博客园蜗牛 cnblogs.com\tdws . 首先提供一种获取hashCode的方法,是一种比较受欢迎的方式,该方法参照了一位园友的 ...

  9. 网站上如何添加显示favicon

    favicon.ico图标是网站的缩略标志,可以显示在浏览器标签.地址栏左边和收藏夹,是展示网站个性的缩略logo标志,也可以说是网站头像.   要添加显示favicon,步骤如下: 1.生成favi ...

  10. 运行第一个PHP程序

    由于PHP比较简单,所以闲来无事学习一下PHP的程序. 之前安装XAMPP出现各种错误,于是下载了PHPStudy,真的十分简单方便,感谢网站开发者. 可以在网站的软件下载中下载,附上首页链接:htt ...