【CSP-S 2019模拟】题解
组:
T1:
简单的莫比乌斯反演之后
得到
其中
设
即
又有
于是可以愉快的杜教筛了
发现手写的哈希表还没有快。。
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
cs int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool 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;
}
inline ll readl(){
char ch=gc();
ll res=0;bool 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;
}
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=9990017;
inline int add(int a,int b){return (a+=b)>=mod?(a-mod):a;}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){static ll r;r=1ll*a*b;return r>=mod?(r%mod):r;}
inline void Add(int&a,int b){a+=b,a>=mod?(a-=mod):0;}
inline void Dec(int &a,int b){a-=b,a+=a>>31&mod;}
inline void Mul(int &a,int b){static ll r;r=1ll*a*b;a=(r>=mod)?(r%mod):r;}
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=3000005,len=N-5;
int fac[mod],ifac[mod];
int pr[N],tot,mu[N],f[N];
ll n,m,B;
bitset<N>vis;
inline int C(int n,int m){
return n<m?0:mul(fac[n],mul(ifac[m],ifac[n-m]));
}
inline int Lucas(int n,int m){
if(n<mod&&m<mod)return C(n,m);
return mul(Lucas(n/mod,m/mod),C(n%mod,m%mod));
}
inline void init(){
fac[0]=ifac[0]=1;
for(int i=1;i<mod;i++)fac[i]=mul(fac[i-1],i);
ifac[mod-1]=Inv(fac[mod-1]);
for(int i=mod-2;i;i--)ifac[i]=mul(ifac[i+1],i+1);
mu[1]=1;
for(int i=2;i<=len;i++){
if(!vis[i])pr[++tot]=i,mu[i]=mod-1;
for(int j=1;j<=tot&&i*pr[j]<=len;j++){
vis[i*pr[j]]=1;
if(i%pr[j]==0)break;
mu[i*pr[j]]=mod-mu[i];
}
}
for(int i=1;i<=len;i++){
for(int j=1,t=Lucas(i,B);i*j<=len;j++)
Add(f[i*j],mul(t,mu[j]));
}
for(int i=1;i<=len;i++)Add(f[i],f[i-1]);
}
map<ll,int>s2;
inline int S(ll x){
if(x<=len)return f[x];
if(s2.count(x))return s2[x];
int res=Lucas(x+1,B+1);
for(ll i=2,nxt;i<=x;i=nxt+1){
nxt=(x/(x/i));
Dec(res,mul((nxt-i+1)%mod,S(x/i)));
}
return s2[x]=res;
}
int main(){
#ifdef Stargazer
freopen("lx.cpp","r",stdin);
#endif
n=readl(),m=readl(),B=read();
init();
int res=0,now=0,last=0;
for(ll i=1,nxt,l=min(n,m);i<=l;i=nxt+1){
nxt=min(n/(n/i),m/(m/i));now=S(nxt);
Add(res,mul(n/i%mod,mul(m/i%mod,dec(now,last))));
last=now;
}
cout<<res;
}
T2:
这个区间的限制很简单
和颜色那道题的骚做法一样
每个区间赋一个随机值
然后用桶存一下
不过的变成树的做法也有丶意思
代码并不想写
T3:
可以维护个位置的状态
好像矩乘跑不过去
暴力打出来答案后用
代码并不想写
组
T2:
考虑预处理表示给个染种颜色的方案
然后考虑
设表示前层,第层用种颜色的方案数
由于颜色集合要不同
所以
虽然有组合数而模数不是质数,但是由于是无序的需要乘一个
就可以把组合数消去了
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
cs int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool 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;
}
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;}
int mod;
inline int add(int a,int b){return (a+=b)>=mod?(a-mod):a;}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){static ll r;r=1ll*a*b;return r>=mod?(r%mod):r;}
inline void Add(int&a,int b){a+=b,a>=mod?(a-=mod):0;}
inline void Dec(int &a,int b){a-=b,a+=a>>31&mod;}
inline void Mul(int &a,int b){static ll r;r=1ll*a*b;a=(r>=mod)?(r%mod):r;}
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=1000005,M=5005;
char xxx;
int n,m,a[N],c[N],f[M][M],g[2][M],lim,fac[M],*tmp;
char yyy;
int main(){
n=read(),m=read(),mod=read();
for(int i=1;i<=n;i++)a[i]=read(),chemx(lim,a[i]);
f[0][0]=1;
fac[0]=1;
for(int i=1;i<=lim;i++)fac[i]=mul(fac[i-1],i);
for(int i=1;i<=lim;i++){
for(int j=1;j<=i;j++)
f[i][j]=add(mul(f[i-1][j],j-1),f[i-1][j-1]);
}
c[1]=m;
for(int i=2;i<=m;i++)c[i]=mul(c[i-1],m-i+1);
int sum=1,now=0;
for(int i=1;i<=n;i++){
now^=1;tmp=f[a[i]];
if(i>1)memset(g[now],0,sizeof(int)*(a[i-2]+1));
for(int j=1;j<=a[i];j++){
Add(g[now][j],mul(dec(mul(sum,c[j]),mul(g[now^1][j],fac[j])),tmp[j]));
}
sum=0;
for(int j=1;j<=a[i];j++)Add(sum,g[now][j]);
}
cout<<sum<<'\n';
}
T3:
考虑是先把个排好,再把第个插入
如果不是最大的一个
那么就相当于是这样
次数是
然后等比数列求和递推即可
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
cs int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
#define gc getchar
inline int read(){
char ch=gc();
int res=0;bool 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;
}
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 int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){static ll r;r=1ll*a*b;return r>=mod?(r%mod):r;}
inline void Add(int&a,int b){a+=b,a>=mod?(a-=mod):0;}
inline void Dec(int &a,int b){a-=b,a+=a>>31&mod;}
inline void Mul(int &a,int b){static ll r;r=1ll*a*b;a=(r>=mod)?(r%mod):r;}
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);}
int inv[100005];
int main(){
int n=read();
inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=mul(mod-mod/i,inv[mod%i]);
int res=0,mt=1;
for(int i=1;i<=n;i++)Add(res,mul(mt-1,inv[i])),Mul(mt,2);
cout<<res;
}