CSP模擬:
T1:求
莫比烏斯反演,設表示
杜教篩中間的,然後整除分塊
中間的捲上一個就完事,還要用到一個定理:=
Code:
#include<bits/stdc++.h>
#define ll long long
#define mod 9990017
using namespace std;
inline ll read(){
ll res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
inline int add(int x,int y){x+=y;if(x>=mod) x-=mod;return x;}
inline int dec(int x,int y){x-=y;if(x<0) x+=mod;return x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline void inc(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void Dec(int &x,int y){x-=y;if(x<0) x+=mod;}
inline void Mul(int &x,int y){x=1ll*x*y%mod;}
inline int ksm(int a,int b){int res=1;for(;b;b>>=1,a=mul(a,a)) if(b&1) res=mul(res,a);return res;}
const int N=3e6+5;
int pri[N],pt[N],tot=0,mu[N],f[N];
int fac[mod],ifac[mod];
int B;
inline int C(int n,int m){if(n<0 || m<0 || n<m) return 0;return 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(int n){
fac[0]=ifac[0]=1;
for(int i=1;i<mod;i++) fac[i]=mul(fac[i-1],i);
ifac[mod-1]=ksm(fac[mod-1],mod-2);
for(int i=mod-2;i;i--) ifac[i]=mul(ifac[i+1],i+1);
mu[1]=1;
for(int i=2;i<=n;i++){
if(!pt[i]) pri[++tot]=i,mu[i]=dec(0,1);
for(int j=1;j<=tot && i*pri[j]<=n;j++){
pt[i*pri[j]]=1;
if(i%pri[j]==0) break;
mu[i*pri[j]]=dec(0,mu[i]);
}
}
for(int i=1;i<=n;i++)
for(int j=1,tmp=lucas(i,B);i*j<=n;j++) inc(f[i*j],mul(tmp,mu[j]));
for(int i=1;i<=n;i++) inc(f[i],f[i-1]);
}
map<ll,int>mp;
int S(ll x){
if(x<=3000000) return f[x];
if(mp.count(x)) return mp[x];
int res=lucas(x+1,B+1);
for(ll i=2,j;i<=x;i=j+1){
j=x/(x/i);
Dec(res,mul(dec(add(j,1),i),S(x/i)));
}
return mp[x]=res;
}
int main(){
ll n=read(),m=read();B=read();
init(3000000);
int ans=0,now=0,last=0;
for(ll i=1,j;i<=min(n,m);i=j+1){
j=min(n/(n/i),m/(m/i));now=S(j);
inc(ans,mul(n/i%mod,mul(m/i%mod,dec(now,last))));
last=now;
}
cout<<ans;
return 0;
}
T2:一個的點集,一共有條弦,每條弦由兩個點組成,每個點僅屬於一條弦,每次詢問給出兩個點,詢問有多少個滿足區間和都不會跨過任意一條弦的恰好一個點,
單調棧預處理每個點往左的極小合法區間左端點,然後每個點向其極小合法區間左端點連邊,形成一棵樹,則不難發現答案就是兩點間的深度
Code:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=2e6+5;
int vis[N],head[N],nxt[N],tot=0;
inline void add(int x,int y){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
int siz[N],hson[N],fa[N],dep[N],rt[N];
int R;
void dfs1(int v){
siz[v]=1;rt[v]=R;
for(int i=head[v];i;i=nxt[i]){
int y=vis[i];
if(y==fa[v]) continue;
fa[y]=v;dep[y]=dep[v]+1;dfs1(y);
siz[v]+=siz[y];
if(siz[y]>siz[hson[v]]) hson[v]=y;
}
}
int top[N];
void dfs2(int v,int T){
top[v]=T;
for(int i=head[v];i;i=nxt[i])
if(top[vis[i]]==-1) dfs2(vis[i],vis[i]==hson[v]?T:vis[i]);
}
inline int lca(int x,int y){
while(top[x]!=top[y])
dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
int lc=dep[x]<dep[y]?x:y;
return dep[lc];
}
int sta[N],tp=0;
int l[N],r[N];
int a[N];
int main(){
#ifdef romiqi
freopen("hotchkiss1.in","r",stdin);
freopen("lx.out","w",stdout);
#endif
int n=read()*2,q=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++){
l[i]=min(i,a[i]);
r[i]=max(i,a[i]);
while(tp && sta[tp]>=l[i]){
l[i]=min(l[i],l[sta[tp]]);
r[i]=max(r[i],r[sta[tp]]);
--tp;
}
sta[++tp]=i;
}
memset(rt,-1,sizeof(rt));
memset(top,-1,sizeof(top));
for(int i=1;i<=n;i++) if(i==r[i]) add(l[i]-1,i);
for(int i=0;i<=n;i++) if(rt[i]==-1){R=i;dfs1(i);dfs2(i,i);}
while(q--){
int x=read(),y=read();
if(x<1 || y<1 || x>n || y>n || rt[x]!=rt[y]) puts("0");
else cout<<lca(x,y)<<"\n";
}
return 0;
}
T3:多次給出一個的矩陣,求用俄羅斯方塊將其恰好填滿的方案數
顯然是狀態壓縮後用矩陣快速冪優化,然而其有常係數線性遞推式,所以可以BM打表+多項式取模
Code:咕咕咕
NOI模擬:
T1:CSPT3
T2:一個sb計數,懶得寫了
T3:一個sb推式子,懶得寫了