取石子
这题分
a
a
a是否等于
1
1
1分类讨论一下,将
[
a
,
b
]
[a,b]
[a,b]设成不可达状态来手玩
s
g
sg
sg函数值
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
int n,a,b;
int main(){
for(ri tt=read();tt;--tt){
n=read(),a=read(),b=read();
bool f=0;
int sum=0;
for(ri x,sg,i=1;i<=n;++i){
x=read();
if(f||x<a)continue;
if(x>=a&&x<=b){f=1;continue;}
else if(a==1)sg=(x-(b+1))%(b+1);
else{
x=(x-b)%(a+b)/a;
if(x<2)sg=x^1;
else sg=x;
}
sum^=sg;
}
if(f){puts("Alice");continue;}
puts(sum?"Alice":"Bob");
}
return 0;
}
序列
d
p
dp
dp神题。
O
r
z
Orz
Orz题解+找高二神仙学姐讨论了一波,大概能看懂
s
t
d
std
std在写啥。
定义几个数组:
f
i
,
j
f_{i,j}
fi,j表示长度限制为
i
i
i,最终填完之后第一个是
j
j
j的概率。
g
i
,
j
g_{i,j}
gi,j表示长度限制为
i
i
i,最终填完之后第一个是
j
j
j的序列和的期望。
p
i
,
j
p_{i,j}
pi,j表示长度限制为
i
i
i,最后弄出来只有第一个为
j
j
j之后的格子都为空的概率。
E
i
,
j
E_{i,j}
Ei,j表示初始一波操作过后第一个放的是
j
j
j,最终填完之后序列和的期望。(注意到填完之后第一个就不一定是
j
j
j了)。
然后维护一个数组
s
s
s,其中
s
i
s_i
si表示长度为
i
i
i的序列的答案来优化转移。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int mod=1e9+7,N=2005;
int f[N][N],g[N][N],p[N][N],E[N][N],s[N],n,m,t,invm;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,a=mul(a,a))if(p&1)ret=mul(ret,a);return ret;}
int main(){
scanf("%d%d%d",&n,&m,&t);
invm=ksm(m,mod-2);
for(ri i=1,up;i<=n;++i){
up=min(t,i+m-1);
for(ri j=1,coe;j<=up;++j){
coe=dec(1,j==t?0:p[i-1][j]);
p[i][j]=add(mul(p[i][j-1],p[i-1][j-1]),j<=m?invm:0);
f[i][j]=mul(p[i][j],coe);
g[i][j]=j==t?add(j,s[i-1]):add(j,mul(dec(s[i-1],mul(p[i-1][j],E[i-1][j])),ksm(coe,mod-2)));
s[i]=add(s[i],mul(f[i][j],g[i][j]));
}
for(ri j=up;j;--j)E[i][j]=add(mul(p[i-1][j],E[i][j+1]),mul(dec(1,j==t?0:p[i-1][j]),g[i][j]));
}
cout<<s[n];
return 0;
}
树
这个就直接上容斥+并查集就完了吧,注意由于是多次询问需要写一个按秩合并的可删除并查集。
代码:
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+5,M=1e6+5;
int anc[N],n,m,mul[M],top=0,siz[N],mu[M],sig=0,mp[N],pri[M],tot=0,val[N];
bool chk[M],vis[M],ban[N],is[M];
struct edge{int u,v,w;}e[N];
struct Node{int id,w;}upd[N];
vector<int>fac[M],coe[M],id[M];
pii stk1[N],stk2[N];
ll ans[N],sum=0;
inline int find(const int&x){return x^anc[x]?find(anc[x]):x;}
inline int get(int x){
if(mul[x])return mul[x];
if(x<2)return mul[x]=x;
int ret=1;
for(ri i=0;i<fac[x].size();++i)ret*=fac[x][i];
return mul[x]=ret;
}
inline void get_coef(int pos,int mul,int a){
if(pos==fac[a].size()){coe[a].push_back(mul);return;}
get_coef(pos+1,mul,a),get_coef(pos+1,fac[a][pos]*mul,a);
}
inline void calc(int x){
if(chk[x])return;
chk[x]=1,get_coef(0,1,x);
}
inline void init(){
for(ri i=2;i<=1000000;++i)if(!vis[i])for(ri j=i;j<=1000000;j+=i)vis[j]=1,fac[j].push_back(i);
for(ri i=1;i<=n;++i)anc[i]=i,siz[i]=1;
for(ri fx,fy,i=1;i<n;++i){
e[i].w=get(e[i].w),calc(e[i].w);
if(ban[i])for(ri j=0;j<coe[e[i].w].size();++j)is[coe[e[i].w][j]]=1;
else for(ri j=0;j<coe[e[i].w].size();++j)id[coe[e[i].w][j]].push_back(i);
}
for(ri i=1;i<=m;++i){
upd[i].w=get(upd[i].w),calc(upd[i].w);
for(ri j=0;j<coe[upd[i].w].size();++j)is[coe[upd[i].w][j]]=1;
}
mu[1]=1;
memset(vis,0,sizeof(vis));
for(ri i=2;i<=1000000;++i){
if(!vis[i])pri[++tot]=i,mu[i]=-1;
for(ri j=1;j<=tot&&i*pri[j]<=1000000;++j){
vis[i*pri[j]]=1;
if(i==i/pri[j]*pri[j]){mu[i*pri[j]]=0;break;}
mu[i*pri[j]]=-mu[i];
}
}
}
inline void merge(int fx,int fy){
fx=find(fx),fy=find(fy);
if(siz[fx]>siz[fy])swap(fx,fy);
++top;
stk1[top]=pii(fx,anc[fx]),anc[fx]=fy;
sum+=(ll)siz[fx]*siz[fy];
stk2[top]=pii(fy,siz[fy]),siz[fy]+=siz[fx];
}
inline void solve(){
for(ri tt=1;tt<=1000000;++tt){
if(!mu[tt])continue;
for(ri qq=0,o;qq<id[tt].size();++qq)o=id[tt][qq],merge(e[o].u,e[o].v);
int tim=top;
ll ps=sum;
for(ri i=0;i<=m;++i){
if(is[tt]){
for(ri j=1;j<=sig;++j)val[mp[j]]=e[mp[j]].w;
for(ri j=1;j<=i;++j)val[upd[j].id]=upd[j].w;
for(ri j=1;j<=sig;++j)if(!(val[mp[j]]%tt))merge(e[mp[j]].u,e[mp[j]].v);
}
ans[i]+=sum*mu[tt];
while(tim^top)anc[stk1[top].fi]=stk1[top].se,siz[stk2[top].fi]=stk2[top].se,--top;
sum=ps;
}
while(top)anc[stk1[top].fi]=stk1[top].se,siz[stk2[top].fi]=stk2[top].se,--top;
sum=0;
}
for(ri i=0;i<=m;++i)cout<<ans[i]<<'\n';
}
signed main(){
n=read();
for(ri i=1;i<n;++i)e[i].u=read(),e[i].v=read(),e[i].w=read();
m=read();
for(ri i=1;i<=m;++i)ban[upd[i].id=mp[++sig]=read()]=1,upd[i].w=read();
sort(mp+1,mp+sig+1),sig=unique(mp+1,mp+sig+1)-mp-1;
init();
solve();
return 0;
}
还有一种更快的写法:
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+5,M=1e6+5,T=205;
int lim=0,n,m,mp[T],sig=0,top=0,anc[N],siz[N],val[N],mu[M],pri[M];
bool vis[M],ban[N],is[M];
struct edge{int u,v,w;}e[N];
struct Node{int id,w;}upd[T];
vector<int>id[M];
ll ans[T],sum=0;
pii s1[N],s2[N];
inline int find(const int&x){return x^anc[x]?find(anc[x]):x;}
inline void merge(int x,int y){
x=find(x),y=find(y);
if(siz[x]>siz[y])swap(x,y);
++top;
s1[top]=pii(x,anc[x]),anc[x]=y;
sum+=(ll)siz[x]*siz[y];
s2[top]=pii(y,siz[y]),siz[y]+=siz[x];
}
inline void init(){
for(ri i=1;i<=n;++i)anc[i]=i,siz[i]=1;
mu[1]=1;
for(ri i=2,tot=0;i<=lim;++i){
if(!vis[i])mu[i]=-1,pri[++tot]=i;
for(ri j=1;j<=tot&&i*pri[j]<=lim;++j){
vis[i*pri[j]]=1;
if(i==i/pri[j]*pri[j]){mu[i*pri[j]]=0;break;}
mu[i*pri[j]]=-mu[i];
}
}
for(ri i=1;i<n;++i){
for(ri j=1;j*j<=e[i].w;++j){
if(e[i].w%j)continue;
if(mu[j]){
if(ban[i])is[j]=1;
else id[j].push_back(i);
}
if(j*j!=e[i].w&&mu[e[i].w/j]){
if(ban[i])is[e[i].w/j]=1;
else id[e[i].w/j].push_back(i);
}
}
}
for(ri i=1;i<=m;++i)for(ri j=1;j*j<=upd[i].w;++j)if(!(upd[i].w%j))is[j]=is[upd[i].w/j]=1;
}
inline void solve(){
for(ri tt=1;tt<=lim;++tt){
if(!mu[tt])continue;
for(ri i=0;i<id[tt].size();++i)merge(e[id[tt][i]].u,e[id[tt][i]].v);
int tim=top;
ll pre=sum;
for(ri i=0;i<=m;++i){
if(is[tt]){
for(ri j=1;j<=sig;++j)val[mp[j]]=e[mp[j]].w;
for(ri j=1;j<=i;++j)val[upd[j].id]=upd[j].w;
for(ri j=1;j<=sig;++j)if(!(val[mp[j]]%tt))merge(e[mp[j]].u,e[mp[j]].v);
}
ans[i]+=sum*mu[tt];
sum=pre;
while(top^tim)anc[s1[top].fi]=s1[top].se,siz[s2[top].fi]=s2[top].se,--top;
}
while(top)anc[s1[top].fi]=s1[top].se,siz[s2[top].fi]=s2[top].se,--top;
sum=0;
}
}
int main(){
n=read();
for(ri i=1;i<n;++i)e[i].u=read(),e[i].v=read(),lim=max(lim,e[i].w=read());
m=read();
for(ri i=1;i<=m;++i)ban[upd[i].id=mp[++sig]=read()]=1,lim=max(lim,upd[i].w=read());
sort(mp+1,mp+sig+1),sig=unique(mp+1,mp+sig+1)-mp-1;
init();
solve();
for(ri i=0;i<=m;++i)cout<<ans[i]<<'\n';
return 0;
}