Codeforce 水题报告
最近做了好多CF的题的说,很多cf的题都很有启发性觉得很有必要总结一下,再加上上次写题解因为太简单被老师骂了,所以这次决定总结一下,也发表一下停课一星期的感想= =
Codeforces 261E Maxim and Calculator
描述:有两个变量a和b,初始值为1和0,每次有两种操作,一个是a=a*b,另一个是b++,求有多少个l<a<r能在p步内达到(p<=100,r<1e9)
首先观察到p最大为100,也就是说最大质因数小于p,打表可得一共大概只有300万个数
考虑dp,设dp[i][j]为当b最多为i时最多须多少次才能a=a*b操作达到j状态,可得f[i][j]=min(f[i-1][j],f[i-1][j/i]+1)
时间复杂度O(np)可以解决这个问题
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 #define maxn 3000001 7 #define maxq 101 8 int f[maxn],p[300],id[maxn],n,r,le,num; 9 bool b[maxn]; 10 int dfs(int x,int y) { 11 id[++n]=y; 12 for (int i=x;i<=num;i++) { 13 if (y*1ll*p[i]>r) break; 14 dfs(i,y*p[i]); 15 } 16 return 0; 17 } 18 int main(){ 19 int le,k; 20 // freopen("1.in","r",stdin); 21 // freopen("1.out","w",stdout); 22 scanf("%d%d%d",&le,&r,&k); 23 for (int i=2;i<=k;i++) { 24 if (!b[i]) p[++num]=i; 25 for (int j=1;j<=num&&i*p[j]<=k;j++) { 26 b[i*p[j]]=1; 27 if (!(i%p[j])) break; 28 } 29 } 30 dfs(1,1); 31 f[1]=0; 32 for (int i=2;i<=n;i++) f[i]=300; 33 sort(id+1,id+1+n); 34 for (int i=1;i<=k;i++) { 35 int t=1; 36 for (int j=1;j<=n;j++) { 37 while (t<=n&&id[t]!=id[j]*i) ++t; 38 if (t>n) break; 39 f[t]=min(f[t],f[j]+1); 40 if ((!b[t])&&(i+f[t]<=k)) b[t]=1; 41 } 42 } 43 int ans=0; 44 for (int i=1;i<=n;i++){ 45 if (b[i]&&id[i]>=le) ++ans; 46 } 47 printf("%d\n",ans); 48 return 0; 49 }
Codeforces 335F Buy One, Get One Free
描述:有很多物品,每买一个物品可选择价格比它小的一种物品作为赠品,求买下所有物品,使其花费最小(n<=500000)
这道题很难理解,首先,把所有价格相同的东西归在一起,记免费获得第i个东西所获得的利润为f[i],做差得g[i],可得g数组一定是单调递减的(每次肯定选最好的比较好啦),然后考虑如何维护g数组,首先记现在处理的物品价格为x共有y个,当前已有m个物品,那么新加入的值是不会影响前面max(0,min(m/2,m+y/2)-y)的值的(因为我要获得更多的利润肯定先用原来获得利润少的机会),接下来我们考虑什么情况下可以更新。
首先当g[i]<y时一定可以直接替换掉,当g[i]>y时,可能存在一种情况,即我支付g[i]元来换取两个x,即多花一个机会获得 2x-g[i]的机会,这样我们就算出了新的g[i]数组,再维护其单调性即可。
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<set> 6 using namespace std; 7 #define maxn 500100 8 typedef long long ll; 9 int a[maxn],n,m; 10 int b[maxn]; 11 typedef pair<int,int> ii; 12 #define fi first 13 #define se second 14 ii s[maxn]; 15 multiset<int> map; 16 bool cmp(int x,int y){return x>y;} 17 int main(){ 18 scanf("%d",&n); 19 for (int i=1;i<=n;i++) scanf("%d",a+i); 20 sort(a+1,a+1+n,cmp); 21 int l=0; 22 ll ans=0; 23 for (int i=1;i<=n;i++) { 24 if (a[i]!=a[i-1]) l++; 25 s[l].fi=a[i];s[l].se++; 26 ans+=a[i]; 27 } 28 n=l; 29 int size=0; 30 for (int i=1;i<=n;i++) { 31 int x=s[i].fi,y=s[i].se; 32 int last=size; 33 size=min(m,(m+y)>>1); 34 int cnt=max(0,size-y); 35 for (int j=size-1;j>=cnt;j--) 36 if (j<map.size()) b[j]=*map.begin(),map.erase(map.begin()); 37 else b[j]=0; 38 for (int j=cnt,k=m-j;j<k&&j<size;j++) 39 if (b[j]<x) b[j]=x; 40 else if (--k<size) b[k]=max(0,2*x-b[j]); 41 map.insert(b+cnt,b+size); 42 m+=y; 43 } 44 45 for (set<int>::iterator it=map.begin();it!=map.end();it++) {ans-=*it;} 46 cout<<ans; 47 return 0; 48 }
Codeforces 293B Distinct Paths
描述:n*m的方格图涂色,已知有若干块以涂色,求涂上k种颜色使所有从左上到右下的路径不经过重复的颜色的方案数(n,m<=1000,k<=10)
其实n,m一定小于k否则无解,但10*10还是太大无法搜索怎么办?我们可以发现,涂到现在还未涂到的颜色本质上还是一样的,所以我们在搜索时遇到还没涂过的颜色只需搜一次即可。
这样还是有几个奇怪的点TLE了,那么我们改变一下搜索策略,从右上搜到左下即可(因为所有颜色都是在一条链上的)
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int b[13][13],n,m,p,ans,a[13][13],hash[13]; 7 int dfs(int u,int v) { 8 if (v==m+1) return dfs(u+1,1); 9 if (u==n+1) {++ans;return 1;} 10 int sum=0,tmp=0;bool flag=0; 11 for (int i=0;i<p;i++) { 12 if (a[u][v]&&a[u][v]!=i+1) continue; 13 if ((b[u-1][v]&(1<<i))||(b[u][v-1]&(1<<i))) continue; 14 hash[i+1]++; 15 b[u][v]=b[u][v-1]|b[u-1][v]|(1<<i); 16 if (hash[i+1]==1) { 17 if (flag) {ans+=tmp;sum+=tmp;} 18 else {tmp=dfs(u,v+1);flag=1;sum+=tmp;} 19 }else sum+=dfs(u,v+1); 20 hash[i+1]--; 21 } 22 return sum; 23 } 24 int main(){ 25 scanf("%d%d%d",&n,&m,&p); 26 if (n+m-1>p) {printf("0\n");return 0;} 27 for (int i=1;i<=n;i++) 28 for (int j=1;j<=m;j++) { 29 scanf("%d",a[i]+j); 30 hash[a[i][j]]++; 31 } 32 dfs(1,1); 33 printf("%d\n",ans); 34 return 0; 35 }
Codeforces 251D Two Sets
描述:两人取n个数,使两个人所有数的异或值的和最大的前提下让某个人的异或值最小,求方案(n<100000)
首先我们可以贪心来做,首先求出所有位的奇偶性,对于奇数两个人的配比一定是1,0,而偶的有可能为0,0或1,1,所以我们让大的偶位数尽量为1,在成立的前提下,再尽量使为奇数的位的1在另一个人的身上,这种判断操作都可以通过高斯消元解异或方程组来解决,然后就行了。
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<bitset> 7 using namespace std; 8 typedef unsigned long long ll; 9 #define maxn 100100 10 #define maxk 64 11 ll c[maxn]; 12 int cnt[maxk]; 13 vector<int> b; 14 vector<bitset<maxn> > a; 15 #define pb push_back 16 int imp[maxn]; 17 int n; 18 inline void add(bitset<maxn> A,int B) { 19 int m=a.size(); 20 for (int i=0;i<m;i++) 21 if (A[imp[i]]) A^=a[i],B^=b[i]; 22 int id=-1; 23 for (int i=0;i<n;i++) if (A[i]) {id=i;break;} 24 if (id==-1) return ; 25 imp[m]=id; 26 for (int i=0;i<m;i++) 27 if (a[i][id]) a[i]^=A,b[i]^=B; 28 a.pb(A),b.pb(B); 29 } 30 int ans[maxn]; 31 int main(){ 32 scanf("%d",&n); 33 for (int i=0;i<n;i++) { 34 scanf("%llu",&c[i]); 35 for (int j=0;j<62;j++) cnt[j]+=(c[i]>>j)&1; 36 } 37 for (int i=61;i>=0;i--) { 38 if (cnt[i]&&!(cnt[i]&1)) { 39 bitset<maxn> t; 40 t.reset(); 41 for (int j=0;j<n;j++) t[j]=(c[j]>>i)&1; 42 add(t,1); 43 } 44 } 45 for (int i=61;i>=0;i--) { 46 if (cnt[i]&&(cnt[i]&1)) { 47 bitset<maxn> t; 48 t.reset(); 49 for (int j=0;j<n;j++) t[j]=(c[j]>>i)&1; 50 add(t,0); 51 } 52 } 53 for (int i=0;i<a.size();i++) ans[imp[i]]=b[i]; 54 for (int i=0;i<n;i++) printf("%d ",2-ans[i]); 55 return 0; 56 }
Codeforces 319D Have You Ever Heard About the Word?
描述:给定一个字符串,每次找最小的(同时最小则取最左的)形如XX的变为X,求最后的字符串(len<=50000)
考试的时候看成最大的了= =
首先我们可以发现所有删除x的不同长度一定少于sqrt(len)种同时删除长度为l的区间一定不会重复,那么我们可以枚举长度并对所有长度相同的区间一起处理。
具体来说我们每次对于一个区间l,设定len/l个哨兵,判断相邻两个哨兵的最长公共前缀和后缀之和是否超过l,如果有,则说明存在一种长度为l的删法之和在暴力判断哪些需要删除
这些操作用hash就能解决了,总的时间复杂度为O(nsqrt(n))
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define maxn 51000 7 typedef unsigned int uint; 8 const int base=31; 9 uint h[maxn],pow[maxn]; 10 char s[maxn],st[maxn]; 11 int b[maxn],n,clo; 12 inline uint hash(int l,int r) {return h[r]-h[l-1]*pow[r-l+1];} 13 inline int findf(int l,int r,int x,int y) { 14 while (l<=r) { 15 int mid=(l+r)>>1; 16 if (hash(x-mid+1,x)==hash(y-mid+1,y)) l=mid+1; 17 else r=mid-1; 18 } 19 return r; 20 } 21 inline int findb(int l,int r,int x,int y) { 22 while (l<=r) { 23 int mid=(l+r)>>1; 24 if (hash(x,x+mid-1)==hash(y,y+mid-1)) l=mid+1; 25 else r=mid-1; 26 } 27 return r; 28 } 29 inline bool check(int l) { 30 for (int i=1;i+l<=n;i+=l) { 31 int f=findf(0,l,i,i+l); 32 int b=findb(0,min(n-i-l+1,l),i,i+l); 33 if (f+b-1>=l) return 1; 34 } 35 return 0; 36 } 37 inline void gethash() {for (int i=1;i<=n;i++) h[i]=h[i-1]*base+s[i]-'a';} 38 inline void work(int l) { 39 clo++; 40 for (int i=1;i+2*l-1<=n;) { 41 if (hash(i,i+l-1)==hash(i+l,i+2*l-1)) { 42 for (int j=i;j<=i+l-1;j++) b[j]=clo; 43 i+=l; 44 }else i++; 45 } 46 int cnt=0; 47 for (int i=1;i<=n;i++) 48 if (b[i]!=clo) st[++cnt]=s[i]; 49 for (int i=1;i<=cnt;i++) s[i]=st[i]; 50 n=cnt; 51 s[n+1]=0; 52 gethash(); 53 } 54 int main(){ 55 scanf("%s",s+1); 56 n=strlen(s+1); 57 gethash(); 58 pow[0]=1; 59 for (int i=1;i<=n;i++) pow[i]=pow[i-1]*base; 60 for (int i=1;i<=n/2;i++) 61 if (check(i)) work(i); 62 printf("%s",s+1); 63 }
Codeforces 280E Sequence Transformation
描述:给定一个非减数列xi要你求出一个数列yi(a<yi-yi-1<b)使sigma(xi-yi)^2最小(n<=300000,xi,yi<q,1<q,a,b<10^9,yi为实数)
这道题真的很精妙,首先我们考虑一个函数fi(x)为当yi=x时的最小开销。然后我们考虑如何由fi-1推到fi
当i-1=1时,可以清楚的看出,为了使其最小,所有的f2(x)中y1的取值必须向f1的极值点靠近,即把f1的极值点左边集体+a,右边集体+b,再加上函数(x2-x)^2。由导数可得,每个函数一定都会有极值点的,因此所有的推法都能这样干。最终答案就是fn的极值点。
那么方案该怎么求呢?我们可以倒过来推,已经知道yn了,那么其他的数都必须尽量靠近fi的极值点,所以我们记录下所有的极值点即可
在实现方面,我们可以用splay直接维护他的导数,3个懒标记即可维护,我的写法足足比其他人少了1/2~~~
比较注意的是极值点可能不在取值范围内,因此边界问题需要比较详细的讨论
(还有一点就是不知为何我的导数并不是连续的,请会的大神告诉我原因QAQ)
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 #define maxn 300010 7 struct node{ 8 double x,y,lz,k,lk,lb; 9 node *ch[2],*pre; 10 node(double _x,double _y,double _k):x(_x),y(_y),k(_k){lk=lb=lz=0;pre=ch[0]=ch[1]=NULL;} 11 inline void update(){ 12 if (lk||lb) { 13 k+=lk;y+=lk*x+lb; 14 if (ch[0]) ch[0]->lk+=lk,ch[0]->lb+=lb+ch[0]->lz*lk; 15 if (ch[1]) ch[1]->lk+=lk,ch[1]->lb+=lb+ch[1]->lz*lk; 16 lk=lb=0; 17 } 18 if (lz) { 19 x+=lz; 20 if (ch[0]) ch[0]->lz+=lz; 21 if (ch[1]) ch[1]->lz+=lz; 22 lz=0; 23 } 24 } 25 inline int d(){return pre->ch[1]==this;} 26 }; 27 inline void rotate(node *u){ 28 node *v=u->pre; 29 if (v->pre) v->pre->update(); 30 v->update();u->update(); 31 if (v->pre) v->pre->ch[v->d()]=u; 32 int d=u->d(); 33 u->pre=v->pre; 34 v->pre=u; 35 if (u->ch[d^1]) u->ch[d^1]->pre=v; 36 v->ch[d]=u->ch[d^1]; 37 u->ch[d^1]=v; 38 } 39 inline void spaly(node *u){u->update();while (u->pre) rotate(u);} 40 node* search(node *u) { 41 if (!u) return 0; 42 u->update(); 43 if (u->y>0) { 44 node *ans=search(u->ch[0]); 45 return ans?ans:u; 46 } 47 return search(u->ch[1]); 48 } 49 int cut(node *r,node* &l){ 50 spaly(r); 51 l=r->ch[0]; 52 r->ch[0]=0; 53 if (l) l->pre=0; 54 } 55 node* rest(node *l){ 56 if (!l) return 0; 57 while (l->ch[1]) l->update(),l=l->ch[1]; 58 l->update(); 59 return l; 60 } 61 node* link(node *l,node *r){ 62 if (l==0) return r;if (r==0) return l; 63 l=rest(l); 64 spaly(l); 65 l->ch[1]=r;r->pre=l; 66 return l; 67 } 68 #define inf 1e10 69 double c[maxn],ans[maxn],w[maxn]; 70 int main(){ 71 int n,q,a,b; 72 scanf("%d%d%d%d",&n,&q,&a,&b); 73 for (int i=1;i<=n;i++) scanf("%lf\n",c+i); 74 node *root=new node(q,q*2-2*c[1],2); 75 for (int i=2;i<=n;i++) { 76 node* r=search(root),*l; 77 cut(r,l); 78 w[i]=r->x-r->y/r->k; 79 if (l)w[i]=max(rest(l)->x,w[i]); 80 if (w[i]>=(i-2)*a+1) { 81 l=link(l,new node(w[i],0,r->k));r=link(new node(w[i],0,0),r); 82 l->lz+=a;r->lz+=b; 83 root=link(l,r); 84 root->lk+=2;root->lb-=2*c[i]; 85 }else { 86 w[i]=(i-2)*a+1; 87 root=link(new node(w[i],0,0),root); 88 root->lz+=b; 89 root->update(); 90 root->lk+=2;root->lb-=2*c[i]; 91 } 92 } 93 node *r=search(root),*l; 94 cut(r,l); 95 double x=r->x-r->y/r->k; 96 if (l) x=max(rest(l)->x,x); 97 if (x<(n-1)*a+1) x=(n-1)*a+1; 98 if (x>q) x=q; 99 for (int i=n;i;i--) { 100 ans[i]=x; 101 if (x-a<w[i]) x-=a; 102 else if (x-b>w[i]) x-=b; 103 else x=w[i]; 104 } 105 double sum=0; 106 for (int i=1;i<=n;i++) { 107 printf("%.10lf ",ans[i]);sum+=(c[i]-ans[i])*(c[i]-ans[i]); 108 } 109 printf("\n%lf\n",sum); 110 return 0; 111 }
Codeforces 261D Maxim and Increasing Subsequence
描述:计算一个重复t次的数列an的最长上升子序列(n<=1e5,maxa<=1e5,t<=1e9,n*maxa<=2e7)
考试的时候脑残了想不到正解写了个暴力居然a了= =
首先可以发现当t>=maxa时直接输出an中不同元素的个数即可,那么我们考虑t<=maxa的情况。
首先记第i次aj的最长上升子序列为f[j],可以发现随着i的增大f[j]肯定是单调不递减的,那么我们可以考虑f[j]是否能增长即可。考虑维护一个g[i] 为所有f[j]>=i的最小a[j],就可以直接转移并维护了。
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<vector> 7 using namespace std; 8 #define maxn 101000 9 int b[maxn],a[maxn],f[maxn]; 10 int main(){ 11 int k,n,t,maxb; 12 scanf("%d%d%d%d",&k,&n,&maxb,&t); 13 while (k--) { 14 for (int i=1;i<=n;i++) scanf("%d",b+i); 15 if (t>=maxb) { 16 sort(b+1,b+1+n); 17 printf("%d\n",unique(b+1,b+1+n)-b-1); 18 continue; 19 } 20 memset(f,0,sizeof(f)); 21 memset(a,0x3f,sizeof(a)); 22 a[0]=0; 23 for (int i=1;i<=t;i++) { 24 for (int j=1;j<=n;j++) { 25 while (a[f[b[j]]]<b[j]) {a[f[b[j]]]=min(a[f[b[j]]],b[j]);f[b[j]]++;} 26 a[f[b[j]]]=min(a[f[b[j]]],b[j]); 27 } 28 } 29 int ans=0; 30 for (int i=1;i<=maxb;i++) ans=max(ans,f[i]); 31 printf("%d\n",ans); 32 } 33 return 0; 34 }
Codeforces 235D Graph Game
描述:在一个n点n边的图上每次随机删一个点并ans+=当前联通块的大小,递归下去,求ans的期望(n<=3000)
可以记f[i][j]为删掉i点时i与j连通的概率,那么ans=sigma(f[i][j])了(clj太***了啊这个根本想不到啊啊啊),然后考虑怎么求f[i][j]。
先考虑树的情况,可以得出联通的概率为1/dist(i,j)(因为不在路径上的点删掉与否是无关的,所以只有那dist(i,j)个)是有用的。
若两点路径没经过环同树的情况,否则记环外路径为x,环两侧路径为y,z则答案为1/(x+y)+1/(x+z)+1/(x+y+z)(由容斥原理可得)
N次dfs即可,时间复杂度为O(n^2)
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define maxn 4010 7 struct edges{int to,next;}edge[maxn*2]; 8 int next[maxn],l; 9 inline void addedge(int x,int y){ 10 edge[++l]=(edges){y,next[x]};next[x]=l; 11 edge[++l]=(edges){x,next[y]};next[y]=l; 12 } 13 bool flag; 14 bool dis[maxn],b[maxn]; 15 int s[maxn],cnt,tot; 16 int dfs1(int u,int pre) { 17 b[u]=1; 18 for (int i=next[u];i;i=edge[i].next) { 19 if (!b[edge[i].to]) { 20 s[++cnt]=edge[i].to; 21 dfs1(edge[i].to,u); 22 if (flag) return 0; 23 cnt--; 24 }else if (edge[i].to!=pre&&cnt) { 25 while (cnt&&s[cnt]!=edge[i].to) dis[s[cnt--]]=1,tot++; 26 flag=1; 27 dis[s[cnt]]=1;tot++; 28 } 29 } 30 } 31 double ans=0; 32 int dfs(int u,int dist,int cnt) { 33 b[u]=1; 34 ans+=1.0/dist; 35 if (cnt>1) { 36 ans+=1.0/(dist+tot-cnt*2+2); 37 ans-=1.0/(dist+tot-cnt); 38 } 39 for (int i=next[u];i;i=edge[i].next) 40 if (!b[edge[i].to]) dfs(edge[i].to,dist+1,cnt+dis[edge[i].to]); 41 } 42 int main(){ 43 int n; 44 scanf("%d",&n); 45 for (int i=1;i<=n;i++) { 46 int x,y; 47 scanf("%d%d",&x,&y); 48 x++,y++; 49 addedge(x,y); 50 } 51 s[cnt=1]=1; 52 dfs1(1,0); 53 memset(b,0,sizeof(b)); 54 for (int i=1;i<=n;i++) {memset(b,0,sizeof(b));dfs(i,1,dis[i]);} 55 printf("%.9lf",ans); 56 return 0; 57 }
Codeforces 226E More Queries to Array
描述:给定一个数组a以及两种操作:1.将l~r设为x 2.询问l~r中sigma a[i]*(i-l+1)^k (n<1e5,k<=5)
直接把询问拆开来可以发现只需维护a[i]*l的0到5次方即可,线段树维护就可以了
因为一点小小的溢出导致查了好久= =,以后打还是得注意多mod一下
Code:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 #define maxn 101000 7 typedef long long ll; 8 struct node { 9 int l,r;ll lz,s[6]; 10 }t[maxn*8]; 11 const ll mod=1000000007ll; 12 #define lc (x<<1) 13 #define rc (lc^1) 14 #define mid ((l+r)>>1) 15 #define ni3 333333336 16 #define ni5 400000003 17 inline ll pow(ll x,int mi) { 18 if (mi==0) return x; 19 if (mi==1) return (1+x)*(x)/2%mod; 20 if (mi==2) return pow(x,1)%mod*(2*x+1)%mod*ni3%mod; 21 if (mi==3) return pow(x,1)*pow(x,1)%mod; 22 if (mi==4) return pow(x,2)*((x*3%mod*x%mod+x*3%mod-1)%mod)%mod*ni5%mod; 23 if (mi==5) return pow(x,3)*((x*2%mod*x%mod+x*2%mod-1)%mod)%mod*ni3%mod; 24 } 25 inline ll quick(int l,int r,int mi) {return (pow(r,mi)-pow(l-1,mi)+mod)%mod;} 26 inline void update(int x) { 27 if (t[x].lz!=-1) { 28 for (int i=0;i<=5;i++) t[x].s[i]=t[x].lz*quick(t[x].l,t[x].r,i)%mod; 29 return ; 30 } 31 for (int i=0;i<=5;i++) t[x].s[i]=(t[lc].s[i]+t[rc].s[i])%mod; 32 } 33 inline void pushback(int x) { 34 if (t[x].lz==-1) return ; 35 t[lc].lz=t[rc].lz=t[x].lz; 36 update(lc);update(rc); 37 t[x].lz=-1; 38 } 39 int a[maxn]; 40 void build(int x,int l,int r) { 41 t[x].l=l,t[x].r=r;t[x].lz=-1; 42 if (l==r) {t[x].lz=a[l];update(x);return ;} 43 build(lc,l,mid);build(rc,mid+1,r); 44 update(x); 45 return ; 46 } 47 void set(int x,int x1,int y1,int z) { 48 int l=t[x].l,r=t[x].r; 49 if (l>y1||r<x1) return ; 50 if (x1<=l&&r<=y1) {t[x].lz=z;update(x);return;} 51 pushback(x); 52 set(lc,x1,y1,z);set(rc,x1,y1,z); 53 update(x); 54 return ; 55 } 56 ll que(int x,int x1,int y1,int z) { 57 int l=t[x].l,r=t[x].r; 58 if (l>y1||r<x1) return 0; 59 if (x1<=l&&r<=y1) return t[x].s[z]; 60 pushback(x); 61 return (que(lc,x1,y1,z)+que(rc,x1,y1,z))%mod; 62 } 63 inline int power(int x,int y){ 64 ll ans=1; 65 for (int i=1;i<=y;i++) (ans*=x)%=mod; 66 return ans; 67 } 68 inline ll que(int l,int r,int k) { 69 int x=1-l; 70 if (k==0) return que(1,l,r,0); 71 if (k==1) return ((que(1,l,r,1)+que(1,l,r,0)*power(x,1)%mod)%mod+mod)%mod; 72 if (k==2) return ((que(1,l,r,2)+que(1,l,r,1)*power(x,1)%mod*2%mod+que(1,l,r,0)*power(x,2)%mod)%mod+mod)%mod; 73 if (k==3) return ((que(1,l,r,3)+que(1,l,r,2)*power(x,1)%mod*3%mod+que(1,l,r,1)*power(x,2)%mod*3%mod+que(1,l,r,0)*power(x,3)%mod)%mod+mod)%mod; 74 if (k==4) return ((que(1,l,r,4)+que(1,l,r,3)*power(x,1)%mod*4%mod+que(1,l,r,2)*power(x,2)%mod*6%mod+que(1,l,r,1)*power(x,3)%mod*4%mod+que(1,l,r,0)*power(x,4)%mod)%mod+mod)%mod; 75 if (k==5) return ((que(1,l,r,5)+que(1,l,r,4)*power(x,1)%mod*5%mod+que(1,l,r,3)*power(x,2)%mod*10%mod+que(1,l,r,2)*power(x,3)%mod*10%mod+que(1,l,r,1)*power(x,4)%mod*5%mod+que(1,l,r,0)*power(x,5)%mod)%mod+mod)%mod; 76 } 77 int main(){ 78 int n,m; 79 scanf("%d%d",&n,&m); 80 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 81 build(1,1,n); 82 while (m--){ 83 int l,r,x;char opt[2]; 84 scanf("%s%d%d%d",opt,&l,&r,&x); 85 switch(opt[0]) { 86 case '=': 87 set(1,l,r,x); 88 break; 89 case '?': 90 printf("%lld\n",que(l,r,x)); 91 break; 92 } 93 } 94 return 0; 95 }
2000个字刚好= =
总结一下吧,cf还是有很多题特别精妙的,没有像某些省选题那么裸,写完这几道题之后感觉自己整个人都不一样了。还是很推荐去刷这几题的
这次终于特别认真的写了一次题解,自己感觉加深了对题目的认识还是挺不错的,后面还有几道code jam的找机会再来写一下
停课一个星期了,感觉自己整个人都特别的颓废,还是读书比较让人提得起精神,不过既然离省选还有一个月,就应该充分利用这一个月的时间来学习一些东西。
这一季要追6部番= =还是挺累的,不过想弃哪部都舍不得啊,不补旧番了吧
这周末好多比赛啊= =,争取都找时间参加一下吧= =
好了瞎说胡扯完了,改题去了