P7887-「MCOI-06」Existence of Truth【构造】

正题

题目连接:https://www.luogu.com.cn/problem/P7887?contestId=52021


题目大意

给出三个长度为\(n\)的序列\(x_i,y_i,z_i\),求一个序列\(a\)满足\(0\leq a_i<10^9+7\)

\[x_i\left(\sum_{j=1}^ia_j\right)+y_i\left(\sum_{j=i}^na_j\right)\equiv z_i(mod\ 10^9+7) \]

如果只有一组解就输出这组解

\(1\leq \sum n\leq 2\times 10^5,1\leq x_i,y_i<10^9+7,0\leq z_i<10^9+7\)


解题思路

看到这个同余就感觉这题是个啥方程的做法类的
\(s_i=\sum_{j=1}^ia_j\)那么有

\[x_is_i+y_i(s_n-s_{i-1})=z_i \]

这样我们就有了\(s_i,s_{i-1},s_n\)之间的关系式,而对于\(s_1\)我们可以直接得到它和\(s_n\)的关系式

\[x_1s_1+y_1s_n=z_1\Rightarrow s_1=\frac{z_1-y_1s_n}{x_1} \]

这样我们可以设\(s_i=A_i+B_is_n\),然后用上面的式子化为

\[s_i=\frac{z_i+y_is_{i-1}-y_is_n}{x_i} \]

推出后面的\(A,B\),最后有

\[s_n=A_n+B_ns_n\Rightarrow s_n=\frac{A_n}{1-B_n} \]

当然\(B_n=1\)时需要判断\(A_n\)是否为\(0\)来得到解数。


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=2e5+10,P=1e9+7;
ll T,n,x[N],y[N],z[N],a[N],b[N],s[N];
ll power(ll x,ll b){
    ll ans=1;x%=P;
    while(b){
        if(b&1)ans=ans*x%P;
        x=x*x%P;b>>=1;
    }
    return ans;
};
signed main()
{
	scanf("%lld",&T);
	while(T--){
		scanf("%lld",&n);
		for(ll i=1;i<=n;i++)
			scanf("%lld%lld%lld",&x[i],&y[i],&z[i]);
		ll inv=power(x[1],P-2);
		a[1]=z[1]*inv%P;b[1]=(P-y[1])*inv%P;
		for(ll i=2;i<=n;i++){
			inv=power(x[i],P-2);
			a[i]=(a[i-1]*y[i]%P+z[i])*inv%P;
			b[i]=(b[i-1]*y[i]%P-y[i]+P)%P*inv%P;
		}
		if(b[n]==1){printf("%lld\n",a[n]?0:P);continue;}
		s[n]=a[n]*power((1-b[n]+P)%P,P-2)%P;
		for(ll i=1;i<n;i++)
			s[i]=(a[i]+b[i]*s[n]%P)%P;
		puts("1");
		for(ll i=1;i<=n;i++)
			printf("%lld ",(s[i]-s[i-1]+P)%P);
		putchar('\n');
	} 
	return 0;
}
posted @ 2021-10-02 00:21  QuantAsk  阅读(435)  评论(0编辑  收藏  举报