T1:
由于模10不好做
考虑分别做模2和模5的情况
乘起来就是总答案
由于有0的情况
可以区间
枚举子区间第一个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:
和广二集训那道有点像
但因为当时的做法和题解不一样所以这个也没想出来
考虑分层
表示前个点,当前层有个的概率
表示到当前距离的期望
枚举每个状态考虑最后一个接在哪里即可
#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;
}