zoukankan      html  css  js  c++  java
  • 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
    ",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
    ");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
    ",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
    ",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("
    %lf
    ",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
    ",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
    ",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
    ",que(l,r,x));
    91                 break;
    92         }
    93     }
    94     return 0;
    95 }
    View Code

    2000个字刚好= =

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

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

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

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

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

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

  • 相关阅读:
    mysql 索引失效的几种情况
    MYSQL行转列-动态修改
    有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列
    C++ 的关键字(保留字)完整介绍
    element-ui组件el-upload自定义上传时界面抖动
    React Hooks 组件卸载时触发的方法
    JS中的事件冒泡和事件捕获
    关于tranform: translate 后,元素被覆盖的问题
    Spring Boot使用@Scheduled时需要注意的坑
    redis的Lua脚本事务注意
  • 原文地址:https://www.cnblogs.com/New-Godess/p/4413843.html
Copyright © 2011-2022 走看看