【CSP-S2019模拟】题解

T1:

由于模10不好做
考虑分别做模2和模5的情况
乘起来就是总答案

由于有0的情况
可以区间dpdp
枚举子区间第一个0的位置递归做
非0区间用带权并查集判一下合法即可

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
    char ch=gc();
    int res=0,f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline void Add(int &a,int b){(a+=b)>=mod?a-=mod:0;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline void Dec(int &a,int b){(a-=b)<0?a+=mod:0;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline void Mul(int &a,int b){a=1ll*a*b%mod;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
cs int N=105;
int n,q,c;
int L[N],R[N],val[N],a[N],_0[N];
int f[N][N],g[N][N],visf[N][N],visg[N][N];
int fa[N],v[N];
int inv[5]={0,1,3,2,4};
inline int find(int x){
	if(fa[x]==x)return x;
	int t=fa[x];
	fa[x]=find(fa[x]);
	v[x]=v[x]*v[t]%c;
	return fa[x];
}
inline bool merge(int x,int y,int k){
	if(!k)return false;
	int f1=find(x),f2=find(y);
	if(f1!=f2){
		fa[f2]=f1,v[f2]=v[x]*inv[k]*inv[v[y]]%c;
		return 1;
	}
	return v[x]*inv[k]%c==v[y];
}
inline int calc_g(int l,int r,vector<int> &now){
	if(visg[l][r])return g[l][r];
	visg[l][r]=1;
	for(int i=l-1;i<=r;i++)fa[i]=i,v[i]=1;
	for(int &x:now){
		if(!merge(L[x]-1,R[x],val[x]))return g[l][r]=0;
	}
	int num=-1;
	for(int i=l-1;i<=r;i++)if(find(i)==i)num++;
	return g[l][r]=ksm(c-1,num);
}
inline int calc_f(int l,int r,vector<int> &now){
	if(!now.size())return ksm(c,r-l+1);
	if(visf[l][r])return f[l][r];
	visf[l][r]=1;

	int res=calc_g(l,r,now);
	for(int i=l;i<=r;i++)if(!_0[i]){
		vector<int> vl,vr;
		for(int &x:now){
			if(L[x]>i)vr.pb(x);
			if(R[x]<i){
				if(val[x]==0)return f[l][r]=res;
				vl.pb(x);
			}
		}
		Add(res,mul(calc_g(l,i-1,vl),calc_f(i+1,r,vr)));
	}
	return f[l][r]=res;
}
inline int solve(){
	memset(_0,0,sizeof(_0));
	for(int i=1;i<=q;i++)
	if(val[i]!=0){
		for(int j=L[i];j<=R[i];j++)_0[j]=1;
	}
	for(int i=1;i<=q;i++)
	if(val[i]==0){
		int fg=0;
		for(int j=L[i];j<=R[i];j++)if(!_0[j])fg=1;
		if(!fg)return 0;
	}
	vector<int> id;
	for(int i=1;i<=q;i++)id.pb(i);
	memset(visg,0,sizeof(visf));
	memset(visf,0,sizeof(visg));
	return calc_f(1,n,id);
}
int main(){
	n=read(),q=read();
	for(int i=1;i<=q;i++)L[i]=read()+1,R[i]=read()+1,a[i]=read();
	for(int i=1;i<=q;i++)val[i]=a[i]%2;
	c=2;int res=solve();
	for(int i=1;i<=q;i++)val[i]=a[i]%5;
	c=5;Mul(res,solve());
	cout<<res;
}

T2:

和广二集训那道有点像
但因为当时的做法和题解不一样所以这个也没想出来
考虑分层dpdp
f[i][j]f[i][j]表示前ii个点,当前层有jj个的概率
gg表示到当前距离的期望
枚举每个状态考虑最后一个接在哪里即可

#include<bits/stdc++.h>
using namespace std;
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#undef gc
#define pb push_back
#define re register
#define cs const
#define pii pair<int,int>
#define fi first
#define se second
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
cs int mod=998244353;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline void Add(int &a,int b){(a+=b)>=mod?a-=mod:0;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline void Dec(int &a,int b){(a-=b)<0?a+=mod:0;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline void Mul(int &a,int b){a=1ll*a*b%mod;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
cs int N=405;
int pw[N*N],tr[N][N],nt[N][N];
int f[N][N],g[N][N],C[N][N],n,p,q;
inline void init(){
	pw[0]=1;
	for(int i=1;i<=n*n;i++)pw[i]=mul(pw[i-1],q);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	tr[i][j]=ksm(dec(1,pw[i]),j);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	nt[i][j]=pw[i*j];
	for(int i=0;i<=n;i++){
		C[i][i]=C[i][0]=1;
		for(int j=1;j<i;j++)
		C[i][j]=add(C[i-1][j-1],C[i-1][j]);
	}
}
int main(){
	n=read(),p=read(),q=1e6-p;
	Mul(p,Inv(1e6)),Mul(q,Inv(1e6));
	init();int res=0;
	f[1][1]=1,g[1][1]=0;
	for(int i=1;i<n;i++)
	for(int j=1;j<=i;j++){
		Add(res,mul(add(f[i][j],g[i][j]),dec(1,pw[j])));
		Add(res,mul(nt[j][n-i],mul(f[i][j],1000000000%mod)));
		for(int k=1;i+k<n;k++){
			int now=mul(tr[j][k],mul(nt[j][n-i-k],C[n-i-1][k]));
			Add(f[i+k][k],mul(f[i][j],now));
			Add(g[i+k][k],mul(now,add(f[i][j],g[i][j])));
		}
	}
	cout<<mul(mul(res,n-1),ksm(10,6*n*n));
}

T3:

看错题了。。。

由于要的是一个连通块的情况
考虑计算强制不是一个连通块的减去
做个背包就可以了

#include<bits/stdc++.h>
using namespace std;
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#undef gc
#define pb push_back
#define re register
#define cs const
#define pii pair<int,int>
#define fi first
#define se second
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
int mod;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline void Add(int &a,int b){(a+=b)>=mod?a-=mod:0;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline void Dec(int &a,int b){(a-=b)<0?a+=mod:0;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline void Mul(int &a,int b){a=1ll*a*b%mod;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
cs int N=47;
int n,ans;
int fac[N],ifac[N],fa[N],inv[N];
int G[N][N],val[N],cnt[N];
inline void init(){
	fac[0]=ifac[0]=1;
	for(int i=1;i<N;i++)fac[i]=mul(fac[i-1],i);
	ifac[N-1]=Inv(fac[N-1]);
	for(int i=N-2;i;i--)ifac[i]=mul(ifac[i+1],i+1);
	inv[0]=inv[1]=1;
	for(int i=2;i<N;i++)inv[i]=mul(mod-mod/i,inv[mod%i]);
}
inline int C(int n,int m){
	if(n<m)return 0;
	int res=ifac[m];
	for(int i=0;i<m;i++)
	Mul(res,n-i);
	return res;
}
vector<int> divi;
inline int gcd(int a,int b){
	return b?gcd(b,a%b):a;
}
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void calc(){
	int tot=0,res=1,siz=divi.size();
	for(int i=1;i<=n;i++)Mul(res,ifac[cnt[i]]);
	for(int &v:divi)Mul(res,inv[v]);
	for(int i=0;i<siz;i++)fa[i]=i,val[i]=0;
	for(int i=0;i<siz;i++){
		int x=divi[i];
		if(x&1)tot+=(x-1)/2;
		else tot+=x/2-1,val[i]=1;
	}
	for(int i=0;i<siz;i++)
	for(int j=i+1;j<siz;j++){
		int g=G[divi[i]][divi[j]];
		int a1=(divi[j]/g)&1,a2=(divi[i]/g)&1;
		if(a1+a2==2){
			int f1=find(i),f2=find(j);
			fa[f1]=f2,tot+=g;
		}
		else if(a1+a2==0)tot+=g;
		else if(a1)val[i]+=g;
		else val[j]+=g;
	}
	for(int i=0;i<siz;i++)
	if(find(i)!=i)val[find(i)]+=val[i];
	for(int i=0;i<siz;i++)
	if(find(i)==i)tot+=val[i]?val[i]-1:0,tot++;
	Add(ans,mul(res,ksm(2,tot)));
}
void dfs(int res,int last){
	if(!res)return calc();
	if(res<last)return;
	for(int i=last;i<=res;i++)
	divi.pb(i),cnt[i]++,dfs(res-i,i),divi.pop_back(),cnt[i]--;
}
int f[N],g[N],t[N];
int main(){
	n=read(),mod=read();
	init();
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)G[i][j]=gcd(i,j);
	for(int i=1;i<=n;i++)ans=0,dfs(i,1),f[i]=ans-1;
	for(int i=1;i<=n;i++)for(int j=1;j<i;j++)Dec(f[i],f[j]);
	g[0]=1,ans=0;
	for(int i=1;i<=n;i++){
		t[i]=dec(f[i],g[i]);
		Add(ans,t[i]);
		for(int j=n;j;j--){
			for(int k=1;i*k<=j;k++)
			Add(g[j],mul(g[j-i*k],C(add(t[i],k-1),k)));
		}
	}cout<<ans;
}
posted @ 2019-10-10 13:31  Stargazer_cykoi  阅读(145)  评论(0编辑  收藏  举报