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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

2000个字刚好= =

总结一下吧,cf还是有很多题特别精妙的,没有像某些省选题那么裸,写完这几道题之后感觉自己整个人都不一样了。还是很推荐去刷这几题的

这次终于特别认真的写了一次题解,自己感觉加深了对题目的认识还是挺不错的,后面还有几道code jam的找机会再来写一下

停课一个星期了,感觉自己整个人都特别的颓废,还是读书比较让人提得起精神,不过既然离省选还有一个月,就应该充分利用这一个月的时间来学习一些东西。

这一季要追6部番= =还是挺累的,不过想弃哪部都舍不得啊,不补旧番了吧

这周末好多比赛啊= =,争取都找时间参加一下吧= =

好了瞎说胡扯完了,改题去了

posted @ 2015-04-10 10:21  New_Godess  阅读(658)  评论(0编辑  收藏  举报