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