[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 }