T1
把两位看成一组,分别维护把 \(0\) 合并进去能否出来 \(0/1\) 和把 \(1\) 合并进去能否出来 \(0/1\)
转移合并时有两种,一种是先把下一次进来的第一位和之前的合并再合并最后三个
另一种是先合并最后三个再合并前面的
Code
#include<bits/stdc++.h>
//#define int long long
#define rint signed
#define mod 998244353
#define F(a,b) for(int i=((a==2)?(0):(a));i<=((a==2)?(1):(a));i++) for(int j=((b==2)?(0):(b));j<=((b==2)?(1):(b));j++)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int T,n,ans;
int trans[10],sta0,sta1,sta;
char s1[10],s2[100010];
int f[100010][4][4];
inline int gsta(int a,int b,int c){return (c<<2)|(b<<1)|(a);}
inline void md(int &x){x=(x>=mod)?(x-mod):(x);}
inline int check(int t0,int t1,int a,int b,int u,int v){
if(trans[gsta(a,b,u)]==1) if((t1>>v)&1) return 1;
if(trans[gsta(a,b,u)]==0) if((t0>>v)&1) return 1;
if(a==1){
if(t1&1) if(trans[gsta(0,b,u)]==v) return 1;
if(t1&2) if(trans[gsta(1,b,u)]==v) return 1;
}else{
if(t0&1) if(trans[gsta(0,b,u)]==v) return 1;
if(t0&2) if(trans[gsta(1,b,u)]==v) return 1;
}
return 0;
}
inline void solve(){
memset(f,0,sizeof(f));ans=0;
scanf("%s%s",s1,s2+1);n=strlen(s2+1);
for(int i=0;i<8;i++) trans[i]=s1[i]-'0';
for(int i=1;i<=n;i++) s2[i]=(s2[i]=='?')?(2):(s2[i]-'0');
F(s2[1],s2[2]){
sta0=trans[gsta(i,j,0)];sta1=trans[gsta(i,j,1)];
sta0=1<<(sta0),sta1=1<<(sta1);
f[2][sta0][sta1]++;
}
for(int now=2;now<=n-3;now+=2) for(int v0=0;v0<4;v0++) for(int v1=0;v1<4;v1++) if(f[now][v0][v1]){
F(s2[now+1],s2[now+2]){
int v00,v01,v10,v11;
v00=check(v0,v1,i,j,0,0);
v01=check(v0,v1,i,j,0,1);
v10=check(v0,v1,i,j,1,0);
v11=check(v0,v1,i,j,1,1);
sta0=(v00)|(v01<<1),sta1=(v10)|(v11<<1);
md(f[now+2][sta0][sta1]+=f[now][v0][v1]);
}
}
if(s2[n]==2){
for(int v0=0;v0<4;v0++) for(int v1=0;v1<4;v1++) if(((v1>>1)&1)) md(ans+=f[n-1][v0][v1]);
for(int v0=0;v0<4;v0++) for(int v1=0;v1<4;v1++) if(((v0>>1)&1)) md(ans+=f[n-1][v0][v1]);
}
else if(s2[n]==1){for(int v0=0;v0<4;v0++) for(int v1=0;v1<4;v1++) if(((v1>>1)&1)) md(ans+=f[n-1][v0][v1]);}
else{for(int v0=0;v0<4;v0++) for(int v1=0;v1<4;v1++) if(((v0>>1)&1)) md(ans+=f[n-1][v0][v1]);}
printf("%d\n",ans);
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
T=read();while(T--) solve();
return 0;
}
T2
发现每个点的 \(SG\) 函数值跟儿子子树内最深的儿子有关
而且只会有两种取值,最大的记录为 \(f1\) 次大的为 \(f2\)
再以树的中心为根时,所有点都会取到 \(f2\) ,因为贡献最大的那个儿子一定会跨过中心
在以任意一个点 \(x\) 为根时,只有 \(x\) 到中心的路径上的点会取到 \(f1\)
用树剖和线段树维护一下异或和就行
实现上有点细节要特判一下中心的取值
Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define lson rt<<1
#define rson rt<<1|1
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,m,rz,rx;
int f1[200010],f2[200010],s1,s2;
int dfn[200010],top[200010],siz[200010],fa[200010],dep[200010],son[200010],id[200010],clo;
vector<int>g[200010];
struct Seg{int a1,a2,b1,b2;bool atag;}st[200010*4];
bool ot;
void dfs0(int x,int fath){dep[x]=dep[fath]+1;fa[x]=fath;for(auto y:g[x]) if(y!=fath) dfs0(y,x);}
void dfs1(int x,int fath,int depth){
fa[x]=fath,siz[x]=1,dep[x]=depth,f2[x]=0;
int maxson=-1;
for(auto y:g[x]) if(y!=fath){
dfs1(y,x,depth+1);siz[x]+=siz[y];f2[x]=max(f2[x],f2[y]+1);
if(maxson<siz[y]) son[x]=y,maxson=siz[y];
}
}
void dfs2(int x,int topf){
top[x]=topf;dfn[x]=++clo;id[clo]=x;
if(!son[x]) return ;dfs2(son[x],topf);
for(auto y:g[x]) if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
}
inline int getson(int x,int y){
if(dfn[son[x]]<=dfn[y]&&dfn[y]+siz[y]-1<=dfn[son[x]]+siz[son[x]]-1) return son[x];
for(;fa[y]!=x;y=top[fa[y]]);return y;
}
inline void pushup(int rt){
st[rt].a1=st[lson].a1^st[rson].a1;
st[rt].a2=st[lson].a2^st[rson].a2;
}
inline void pushdown(int rt){
if(st[rt].atag){
st[lson].atag^=1,st[rson].atag^=1;
st[lson].a1^=st[lson].b1,st[lson].a2^=st[lson].b2;
st[rson].a1^=st[rson].b1,st[rson].a2^=st[rson].b2;
st[rt].atag=0;
}
}
void build(int rt,int l,int r){
if(l==r) return st[rt].a1=st[rt].b1=f2[id[l]],st[rt].a2=st[rt].b2=f1[id[l]]^f2[id[l]],void();
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(rt);
st[rt].b1=st[lson].b1^st[rson].b1;
st[rt].b2=st[lson].b2^st[rson].b2;
}
void upd(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R) return st[rt].atag^=1,st[rt].a1^=st[rt].b1,st[rt].a2^=st[rt].b2,void();
int mid=(l+r)>>1;pushdown(rt);
if(L<=mid) upd(lson,l,mid,L,R);
if(R>mid) upd(rson,mid+1,r,L,R);
pushup(rt);
}
int query1(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R) return st[rt].a1;
int mid=(l+r)>>1,res=0;pushdown(rt);
if(L<=mid) res^=query1(lson,l,mid,L,R);
if(R>mid) res^=query1(rson,mid+1,r,L,R);
return res;
}
int query2(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R) return st[rt].a2;
int mid=(l+r)>>1,res=0;pushdown(rt);
if(L<=mid) res^=query2(lson,l,mid,L,R);
if(R>mid) res^=query2(rson,mid+1,r,L,R);
return res;
}
inline void upd(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
upd(1,1,n,dfn[top[x]],dfn[x]);x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
if(dfn[x]==1) ot^=1;upd(1,1,n,dfn[x],dfn[y]);
}
inline void upd(int x){
if(x==rx) return upd(1,1,n,1,n),ot^=1,void();
if(dfn[x]<=dfn[rx]&&dfn[rx]+siz[rx]-1<=dfn[x]+siz[x]-1){
x=getson(x,rx);
if(dfn[x]-1>=1) upd(1,1,n,1,dfn[x]-1),ot^=1;
if(dfn[x]+siz[x]<=n) upd(1,1,n,dfn[x]+siz[x],n);
return ;
}
if(dfn[x]==1) ot^=1;upd(1,1,n,dfn[x],dfn[x]+siz[x]-1);
}
inline int solve(int x){
int res=query1(1,1,n,2,n),sx=0;rx=x;
if(x!=rz) sx=getson(rz,x);
while(top[x]!=top[rz]){
res^=query2(1,1,n,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if(dfn[rz]+1<=dfn[x]) res^=query2(1,1,n,dfn[rz]+1,dfn[x]);
if(ot) res^=((sx==s1)?(f2[s2]+1):(f2[s1]+1));
return res;
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
n=read(),m=read();rx=1;ot=1;f1[0]=f2[0]=-1;
for(int i=1,x,y;i<n;i++){
x=read(),y=read();
g[x].emplace_back(y);
g[y].emplace_back(x);
}
dep[1]=0;dfs0(1,0);for(int i=1;i<=n;i++) if(dep[i]>dep[rz]) rz=i;
dep[rz]=0;dfs0(rz,0);for(int i=1;i<=n;i++) if(dep[i]>dep[rz]) rz=i;
for(int d=(dep[rz]+1)>>1;dep[rz]!=d;rz=fa[rz]);
dep[rz]=0;dfs1(rz,0,1);dfs2(rz,rz);
for(auto y:g[rz]){
if(f2[y]>=f2[s1]) s2=s1,s1=y;
else if(f2[y]>=f2[s2]) s2=y;
}
for(auto y:g[rz]){
int v=(y==s1)?(f2[s2]):(f2[s1]);
for(int i=dfn[y];i<dfn[y]+siz[y];i++) f1[id[i]]=dep[id[i]]+v;
}
build(1,1,n);
for(int i=1,op,x,y,z;i<=m;i++){
op=read();
if(op==1){x=read(),y=read(),z=read();upd(x,y);}
else{x=read(),z=read();upd(x);}
printf("%lld\n",solve(z));fflush(stdout);
}
return 0;
}
T3
要求的东西可以转化成这样 \(\frac{e(V)}{|V|-1}>lim\) 其中 \(V\) 为选定的点集
移项可以得到 \(e(V)-|V|lim>-lim\) 可以转化成最大权闭合子图的形式
由每条边向他的两个端点连边,源点先边连 \(1\) ,点向汇点连 \(lim\)
发现直接跑网络流可能会什么也不选,于是每次强制选择一个点
这里用到了一个退流的技巧,用网络流跑一遍 \(u->S\) 和 \(T->v\)
把边的流量改成 \(0\) ,最后再跑一遍网络流,就能把 \(u,v\) 这条边带来的影响去掉
Code
#include<bits/stdc++.h>
//#define int long long
#define rint signed
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,m,lim,S,T,ans;
int dis[8010],q[8010],h,t;
int head[8010],HD[8010],ver[40010],edge[40010],to[40010],tot=1;
inline void add(int x,int y,int z){
ver[++tot]=y;edge[tot]=z;to[tot]=head[x];head[x]=tot;
ver[++tot]=x;edge[tot]=0;to[tot]=head[y];head[y]=tot;
}
inline bool bfs(){
for(int i=1;i<=n+m+2;i++) dis[i]=inf;
dis[S]=0;q[h=t=1]=S;memcpy(head,HD,sizeof(head));
while(h<=t){
int x=q[h++];
for(int i=head[x];i;i=to[i]) if(edge[i]){
int y=ver[i];
if(dis[y]>dis[x]+1) dis[y]=dis[x]+1,q[++t]=y;
}
if(x==T) return true;
}
return false;
}
int dfs(int x,int in){
if(x==T) return in;
int res=in,go;
for(int i=head[x];i;head[x]=i=to[i]) if(edge[i]){
int y=ver[i];
if(dis[y]==dis[x]+1){
go=dfs(y,min(res,edge[i]));
if(go) edge[i]-=go,edge[i^1]+=go,res-=go;
else dis[y]=0;
}
if(!res) break;
}
return in-res;
}
inline int dinic(int s,int t){
S=s,T=t;int res=0;
while(bfs()) res+=dfs(S,inf);return res;
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("socialbutterfly.in","r",stdin);
freopen("socialbutterfly.out","w",stdout);
n=read(),m=read(),lim=read();S=n+m+1,T=n+m+2;
for(int i=1,x,y;i<=m;i++){
x=read(),y=read();
add(i+n,x,inf),add(i+n,y,inf);
add(S,i+n,1);
}
for(int i=1;i<=n;i++) add(i,T,lim);memcpy(HD,head,sizeof(head));
for(int i=1;i<=n;i++){
for(int j=head[i];j;j=to[j]){int y=ver[j];if(y==T){edge[j]=0,edge[j^1]=0;break;}}
ans-=dinic(i,n+m+1);ans+=dinic(n+m+1,n+m+2);
if(m-ans>0) puts("Yes"),exit(0);
for(int j=head[i];j;j=to[j]){int y=ver[j];if(y==T){edge[j]=lim,edge[j^1]=0;break;}}
}
puts("No");
return 0;
}