[cf1495E]Qingshan and Daniel

选择其中卡片总数较少的一类,当相同时选择$t_{1}$所对应的一类(以下记作$A$类)

如果$t_{1}$不是$A$类,就先对$t_{1}$操作一次(即令$a_{1}$减少1)

下面,问题即不断删去$A$类中的一张卡片,再删除另一类中的一张卡片,直至$A$中卡片被删光

事实上,$A$类中卡片删除顺序与最终另一类卡片剩余卡片的位置无关,具体证明考虑交换$A$中两张相邻卡片的删除顺序,并分类讨论来说明不影响即可

由此,不妨假设$A$类卡片是从左到右依次删除(即删完一叠后删除下一叠),每一张删除时都找到下一叠未完全删除的非$A$类卡片,并删除其中一张

对于这个过程,可以用下述方法维护:

记录一个变量$s$,表示$A$中当前还有几张卡片没有对应的删除

若当前为$A$类,令$s$加上这一叠的卡片数

若当前为$B$类,从中删除$\min(s,这一叠的卡片数)$,同时$s$也减去这个值

由于是环,所以重复一次即可

时间复杂度为$o(n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 5000005
 4 #define mod 1000000007
 5 #define ll long long
 6 int n,m,p,x,y,seed,base,a[N],t[N],ans[N];
 7 ll s,tot[3];
 8 int rnd(){
 9     int ans=seed;
10     seed=(1LL*seed*base+233)%mod;
11     return ans;
12 }
13 int main(){
14     scanf("%d%d",&n,&m);
15     int lst=0;
16     for(int i=1;i<=m;i++){
17         scanf("%d%d%d%d",&x,&y,&seed,&base);
18         for(int j=lst+1;j<=x;j++){
19             t[j]=rnd()%2+1;
20             a[j]=rnd()%y+1;
21         }
22         lst=x;
23     }
24     for(int i=1;i<=n;i++)tot[t[i]]+=a[i];
25     if (tot[1]!=tot[2]){
26         if (tot[1]<tot[2])p=1;
27         else p=2;
28     }
29     else p=t[1];
30     if (p!=t[1]){
31         a[1]--;
32         ans[1]++;
33     }
34     for(int i=1;i<=n;i++)
35         if (t[i]==p){
36             s+=a[i];
37             ans[i]+=a[i];
38             a[i]=0;
39         }
40         else{
41             int x=min((ll)a[i],s);
42             ans[i]+=x;
43             s-=x;
44             a[i]-=x;
45         }
46     for(int i=1;i<=n;i++)
47         if (t[i]==p){
48             s+=a[i];
49             ans[i]+=a[i];
50             a[i]=0;
51         }
52         else{
53             int x=min((ll)a[i],s);
54             ans[i]+=x;
55             s-=x;
56             a[i]-=x;
57         }
58     ans[0]=1;
59     for(int i=1;i<=n;i++)ans[0]=((ans[i]^(1LL*i*i))+1)%mod*ans[0]%mod;
60     printf("%d",ans[0]);
61 } 
View Code

 

posted @ 2021-05-07 12:48  PYWBKTDA  阅读(60)  评论(0编辑  收藏  举报