[cf1540C]Converging Array

性质1:对$i$操作后,$a_{i}+a_{i+1}$的值不变

性质2:若初始$a_{i+1}-a_{i}\le b_{i}$,则最终$a_{i+1}-a_{i}=b_{i}$

换言之,不断合并$a_{i+1}-a_{i}\le b_{i}$,对于合并后的每一段,根据总和和差值即可解出

在此基础上,假设$1$所在段$[1,i]$与$(i,j]$合并,合并后$a_{i}$被看作$a_{i+1}-a_{i}=b_{i}$

同时$a_{i}\downarrow\ \Longrightarrow \sum_{k=1}^{i}a_{k}\downarrow\ \Longrightarrow a_{1}\downarrow$($\uparrow$同理),即初始合并会减小$a_{1}$,而最终合并会增大$a_{1}$

换言之,$a_{1}$是所有"情况"中的最小值,进而$a_{1}\ge x\iff \forall i\in [1,n],1$所在段为$[1,i]$时$a_{1}\ge x$

具体的,$1$所在段为$[1,i]$时$a_{1}=\frac{\sum_{j=1}^{i}a_{j}-\sum_{j=1}^{i-1}(i-j)b_{j}}{i}$,进而限制即$\sum_{j=1}^{i}a_{j}\ge ix+\sum_{j=1}^{i-1}(i-j)b_{j}$

暴力dp并使用前缀和优化,单次dp时间复杂度为$o(n^{2}V_{c})$

记$B_{i}=\sum_{j=1}^{i-1}(i-j)b_{j}$,若$\exists i\in [1,n],ix+B_{i}>iV_{c}$或$\forall i\in [1,n],ix+B_{i}\le 0$,显然答案为0或$\prod_{i=1}^{n}(c_{i}+1)$

若两者均不满足,即$x\in (\min\frac{-B_{i}}{i},\min \frac{iV_{c}-B_{i}}{i}]$,显然其中恰有$V_{c}$个元素,使用上述dp即可

时间复杂度为$o(n^{2}V_{c}^{2}+qn)$(检验),可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 105
 4 #define M 10005
 5 #define mod 1000000007
 6 #define ll long long
 7 int n,q,x,cmx,cans,c[N],b[N],B[N],ans[M<<1],f[N][M];
 8 int main(){
 9     scanf("%d",&n);
10     for(int i=1;i<=n;i++)scanf("%d",&c[i]);
11     for(int i=1;i<n;i++)scanf("%d",&b[i]);
12     cans=1;
13     for(int i=1;i<=n;i++){
14         cmx=max(cmx,c[i]);
15         cans=(ll)cans*(c[i]+1)%mod;
16     }
17     for(int i=1;i<=n;i++)
18         for(int j=1;j<i;j++)B[i]+=(i-j)*b[j];
19     memset(ans,-1,sizeof(ans));
20     scanf("%d",&q);
21     while (q--){
22         scanf("%d",&x);
23         bool flag=0;
24         for(int i=1;i<=n;i++)
25             if (i*x+B[i]>i*cmx){
26                 flag=1,printf("0\n");
27                 break;
28             }
29         if (flag)continue;
30         for(int i=1;i<=n;i++)
31             if (i*x+B[i]>0)flag=1;
32         if (!flag){
33             printf("%d\n",cans);
34             continue;
35         }
36         if (ans[x+M]>=0){
37             printf("%d\n",ans[x+M]);
38             continue;
39         }
40         memset(f,0,sizeof(f));
41         ans[x+M]=0,f[0][0]=1;
42         for(int i=1;i<=n;i++)
43             for(int j=0;j<=i*cmx;j++){
44                 f[i-1][j]=(f[i-1][j]+f[i-1][j-1])%mod;
45                 if (j>=i*x+B[i]){
46                     f[i][j]=f[i-1][j];
47                     if (j>c[i])f[i][j]=(f[i][j]-f[i-1][j-c[i]-1]+mod)%mod;
48                 }
49             }
50         for(int j=0;j<M;j++)ans[x+M]=(ans[x+M]+f[n][j])%mod;
51         printf("%d\n",ans[x+M]);
52     }
53     return 0;
54 }
View Code

 

posted @ 2022-03-11 16:47  PYWBKTDA  阅读(45)  评论(0编辑  收藏  举报