zoukankan      html  css  js  c++  java
  • CF1540C Converging Array 题解

    Codeforces C1
    Codeforces C2
    Luogu C1
    Luogu C2

    Problem.

    定义每次序列 \(b\) 作用于序列 \(a\) 的操作为,选择一个 \(i\)

    • \(a_i\leftarrow\min\left(a_i,\frac{a_i+a_{i+1}-b_i}2\right)\)
    • \(a_{i+1}\leftarrow\max\left(a_{i+1},\frac{a_i+a_{i+1}+b_i}2\right)\)

    定义 \(F(a,b)\) 表示经过无限次 \(b\) 作用于 \(a\) 的操作后,\(a_1\) 的大小。
    问有多少个 \(\{a_i\}\),满足:

    • \(\forall i\in[1,n],a_i\in[1,c_i]\)
    • \(F(a,b)\ge x\)

    Solution.

    观察性质。
    发现每次变化的 \(\min\)\(\max\) 取的东西是一样的。
    每次变化条件是 \(a_{i+1}-a_i< b_i\)
    变化后 \(a'_i+a'_{i+1}=a_i+a_{i+1}\)
    最后一定会有 \(\forall i\in[1,n),a_{i+1}-a_i\ge b_i\)
    我们考虑怎么求出 \(a_1\) 呢。
    必定存在一个唯一的 \(p\),满足

    • \(\forall i\in[1,p),a'_{i+1}-a'_i=b_i\)
    • \(a'_{p+1}-a'_p\ne b_p\)

    然后我们发现如果刚开始 \(a_{x+1}-a_x>b_x\) 了,\(a_x\)\(a_{x+1}\) 就不会变。
    所以我们有 \(\sum_{i=1}^pa_i=\sum_{i=1}^pa'_i\)
    这样就可以求出 \(a_1\) 了,为 \(\frac{\sum_{i=1}^pa_i-\sum_{i=1}^{p-1}(p-i)\cdot b_i}{p}\)
    我们发现,如果枚举错了,\(p'\) 并不是满足上面条件的话。
    我们可以发现有两种情况

    • \(p'< p\),这样的话我们发现 \(\sum_{i=1}^{p'}a'_i<\sum_{i=1}^pa'_i\)
      有解出来的 \(a_{wrong,1}>a_1\)
    • \(p'>p\),这样的话我们发现存在一个 \(a_{x+1}-a_x>b_x\)
      同时也有解出来的 \(a_{wrong,1}>a_1\)

    所以我们在不知道 \(p\) 的情况下求出所有的 \(a_{i,1}\) 最小值即可。
    最小值都要 \(\ge x\),则有 \(\forall p\in[1,n],\frac{\sum_{i=1}^pa_i-\sum_{i=1}^{p-1}(p-i)\cdot b_i}{p}\ge x\)
    \(sa_i\ge x\cdot i+\sum_{j=1}^{i-1}(i-j)\cdot b_j\)
    发现左边值域是 \(100^2\),可以直接背包


    发现不同的 \(x\) 只有 \(100\) 种。
    思考它们有没有什么相同的性质,发现没有。
    桥豆麻袋!\(O(100^4)\) 可过,然后就做完了。

    Coding.

    点击查看 C1 代码
    //是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了……{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	char ch=getchar(),bz=0;x=0;
    	for(;ch<48||ch>57;ch=getchar()) if(!(ch^45)) bz=1;
    	for(;ch>=48&&ch<=57;ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
    	bz?x=-x:0;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}/*}}}*/
    const int P=1e9+7;int n,q,c[105],b[105],X,lm[105],dp[105][10005],s[105][10005];
    int main()
    {
    	read(n);for(int i=1;i<=n;i++) read(c[i]);
    	for(int i=1;i<n;i++) read(b[i]);
    	read(q),read(X);if(X>100) return puts("0"),0;
    	for(int i=1;i<=n;i++) for(int j=1;j<i;j++) lm[i]+=(i-j)*b[j];
    	for(int i=1;i<=n;i++) lm[i]+=i*X,lm[i]=max(lm[i],0);
    	int m=0;for(int i=1;i<=n;i++) m+=c[i];
    	dp[0][0]=0;for(int i=0;i<=m;i++) s[0][i]=1;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=lm[i];j<=m;j++)
    		{
    			int qw=(j-c[i]-1<0?0:s[i-1][j-c[i]-1]);
    			dp[i][j]=(s[i-1][j]-qw+P)%P;
    		}
    		for(int j=lm[i];j<=m;j++) s[i][j]=(s[i][j-1]+dp[i][j])%P;
    	}
    	return printf("%d\n",s[n][m]),0;
    }
    
    点击查看 C2 代码
    //是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了……{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	char ch=getchar(),bz=0;x=0;
    	for(;ch<48||ch>57;ch=getchar()) if(!(ch^45)) bz=1;
    	for(;ch>=48&&ch<=57;ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
    	bz?x=-x:0;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}/*}}}*/
    const int P=1e9+7;int n,q,m,c[105],b[105],X,lm[105];
    int LM[105],dp[105][10005],s[105][10005],rs[505],sc[105];
    inline int solve(int X)
    {
    	for(int i=1;i<=n;i++) {lm[i]=max(LM[i]+i*X,0);if(lm[i]>m) return 0;}
    	dp[0][0]=1;for(int i=0;i<=m;i++) s[0][i]=1;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=lm[i];j<=m;j++)
    		{
    			int ps=j-c[i]-1,qw=(ps<lm[i-1]||ps>m?0:s[i-1][ps]);
    			dp[i][j]=((j<lm[i-1]||j>m?0:s[i-1][j])-qw+P)%P;
    		}s[i][lm[i]]=dp[i][lm[i]];
    		for(int j=lm[i]+1;j<=m;j++) s[i][j]=(s[i][j-1]+dp[i][j])%P;
    	}
    	return s[n][m];
    }
    int main()
    {
    	read(n);for(int i=1;i<=n;i++) read(c[i]);
    	for(int i=1;i<n;i++) read(b[i]);
    	for(int i=1;i<=n;i++) for(int j=1;j<i;j++) LM[i]+=(i-j)*b[j];
    	for(int i=1;i<=n;i++) m+=c[i],sc[i]=sc[i-1]+c[i];
    	int neg=1;for(int i=1;i<=n;i++) neg=1ll*neg*(c[i]+1)%P;
    	int L=1e9,R=1e9;for(int i=1;i<=n;i++) L=min(L,-LM[i]/i)-1,R=min(R,(100*n-LM[i])/i)+1;
    	for(int i=L;i<=R;i++) rs[i-L]=solve(i);
    	read(q);for(int x;q--;) read(x),printf("%d\n",x<L?neg:(x>R?0:rs[x-L]));
    	return 0;
    }
    
  • 相关阅读:
    查询父节点parentNode
    008-流程控制 case 语句
    007-流程控制 if 语句
    006-条件判断
    005-sort 命令使用
    004-sed 命令使用
    003-awk 命令使用
    002-printf 命令用法
    001-cut 的用法
    002-变量
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15174773.html
Copyright © 2011-2022 走看看