传送门
题解:
首先根据中国剩余定理,我们知道 的 在 有唯一解。
所以我们对于 和 下求解然后乘法原理乘起来即可。
那么考虑怎么算合法方案,首先考虑没有 的话每个限制都可以表示为两个前缀积之比。
那么没有 的情况可以用带权并查集来判断是否合法,那么最后考虑自由位置的数量即可得到方案。
如果有 怎么办。。。
考虑区间DP, 表示区间 的答案,同时对于所有非零的限制,我们不会把它拆开。然后枚举这个区间第一个 的位置,前面用非零的做法来算,后面的继续用 计算。
实现直接记忆化搜索即可。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
cs int mod=1e9+7;
inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));return res;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
class ProductQuery{
private:
static cs int N=1e2+7;
int inv[5]={0,1,3,2,4};
int n,m,b,notzero[N];
int f[N][N],g[N][N];
struct atom{int l,r,v;};
int fa[N],a[N];
inline int gf(int u){
if(fa[u]==u)return u;
int tmp=gf(fa[u]);
a[u]=a[u]*a[fa[u]]%b;
return fa[u]=tmp;
}
inline bool merge(int u,int v,int val){
if(!val)return false;
int fu=gf(u),fv=gf(v);
if(fu!=fv){
fa[fu]=fv;
a[fu]=a[v]*inv[a[u]]*inv[val]%b;
return true;
}
else return a[v]*inv[a[u]]%b==val;
}
inline int F(int l,int r,cs std::vector<atom> &vec){//no zero
if(!vec.size())return power(b-1,r-l+1);
int &ans=f[l][r];if(~ans)return ans;
for(int re i=l-1;i<=r;++i)fa[i]=i,a[i]=1;
for(auto &t:vec)if(!merge(t.l-1,t.r,t.v))return ans=0;
int ct=0;for(int re i=l-1;i<=r;++i)if(fa[i]==i)++ct;
return ans=power(b-1,ct-1);
}
inline int G(int l,int r,cs std::vector<atom> &vec){
if(!vec.size())return power(b,r-l+1);
int &ans=g[l][r];if(~ans)return ans;
ans=F(l,r,vec);
for(int re i=l;i<=r;++i)if(!notzero[i]){
bool flag=true;
std::vector<atom> v1,v2;
for(auto &t:vec){
if(t.r<i){
if(t.v==0){flag=false;break;}
v1.push_back(t);
}
if(t.l>i)v2.push_back(t);
}
if(flag)Inc(ans,mul(F(l,i-1,v1),G(i+1,r,v2)));
}
return ans;
}
inline int solve(cs std::vector<atom> &vec){
memset(notzero,0,sizeof notzero);
for(auto &t:vec){
int l=t.l,r=t.r,v=t.v;
if(v)for(int re i=l;i<=r;++i)notzero[i]=true;
}
for(auto &t:vec){
int l=t.l,r=t.r,v=t.v;
if(!v){
bool flag=true;
for(int re i=l;i<=r;++i)flag&=notzero[i];
if(flag)return 0;
}
}
memset(f,-1,sizeof f);
memset(g,-1,sizeof g);
return G(1,n,vec);
}
public:
ProductQuery(){}
int theInput(int N,std::vector<int> ql,
std::vector<int> qr,std::vector<int> ans){
n=N,m=ql.size();
b=2;int res=1;
std::vector<atom> vec;
for(int re i=0;i<m;++i)
vec.push_back((atom){ql[i]+1,qr[i]+1,ans[i]&1});
Mul(res,solve(vec));b=5;
for(int re i=0;i<m;++i)vec[i].v=ans[i]%5;
return mul(res,solve(vec));
}
};
#ifdef zxyoi
ProductQuery Solver;
signed main(){
std::cout<<Solver.theInput(
58,
{5, 5},
{8, 8},
{1, 2}
)<<"\n";
return 0;
}
#endif
转载:https://blog.csdn.net/zxyoi_dreamer/article/details/102466876
查看评论