NOIP58

T1 lesson5!
正方拓扑最短路,然后在值域上开一个权值线段树/堆/multiset。
拓扑序枚举每个点,删去这个点贡献的答案,统计ans,再加上。

#include<bits/stdc++.h>
#define ls p*2
#define rs p*2+1
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*w;
}
int _max(int a,int b){return a>b?a:b;}
int _min(int a,int b){return a<b?a:b;}
const int N=1100000,M=5100000,INF=0x7fffffff;
int head[2][N],cnt,n,m,dis[2][N],du[2][N],ansx,ans;
struct rec
{
	int nxt,v;
}e[2][M];
int change[N];
int num[N],res[M];
void clear()
{
	cnt=0;
	memset(head,0,sizeof(head));
	memset(change,0,sizeof(change));
	memset(du,0,sizeof(du));
	memset(res,0,sizeof(res));
	memset(dis,0,sizeof(dis));
	memset(num,0,sizeof(num));
	ansx=1;ans=n;
}
void add(bool id,int x,int y)
{
	e[id][++cnt].v=y;
	e[id][cnt].nxt=head[id][x];
	head[id][x]=cnt;
}
void pushup(int p)
{
	res[p]=_max(res[ls],res[rs]);
}
void add(int p,int l,int r,int k)
{
	if(l==r)
	{
		num[l]++;
		if(num[l]>0)
			res[p]=l;
		else
		{
			num[l]=0;
			res[p]=-INF;
		}
		return;
	}
	int mid=(l+r)>>1;
	if(k<=mid)
		add(ls,l,mid,k);
	else
		add(rs,mid+1,r,k);
	pushup(p);
}
void del(int p,int l,int r,int k)
{
	if(l==r)
	{
		num[l]--;
		if(num[l]>0)
			res[p]=l;
		else
		{
			num[l]=0;
			res[p]=-INF;
		}
		return;
	}
	int mid=(l+r)>>1;
	if(k<=mid)
		del(ls,l,mid,k);
	else
		del(rs,mid+1,r,k);
	pushup(p);
}
void topo(int ty)
{
	queue<int>q;
	for(int i=1;i<=n;i++)
	{
		if(!du[ty][i])
		{
			if(!ty)
				change[++change[ty]]=i;
			q.push(i);
		}
	}
	while(!q.empty())
	{
		int x=q.front();q.pop();
		for(int i=head[ty][x];i;i=e[ty][i].nxt)
		{
			if(dis[ty][e[ty][i].v]<dis[ty][x]+1)
				dis[ty][e[ty][i].v]=dis[ty][x]+1;
			if(!(--du[ty][e[ty][i].v]))
			{
				if(!ty)
					change[++change[ty]]=e[ty][i].v;
				q.push(e[ty][i].v);
			}
		}
	}
}
int main()
{
	freopen("johnny.in","r",stdin);
	freopen("johnny.out","w",stdout);
	int T=read();
	while(T--)
	{
		n=read();m=read();
		cnt=1;
		memset(head,0,sizeof(head));
		memset(change,0,sizeof(change));
		memset(du,0,sizeof(du));
		memset(res,0,sizeof(res));
		memset(dis,0,sizeof(dis));
		memset(num,0,sizeof(num));
		ansx=1;ans=n;
		for(int i=1;i<=m;i++)
		{
			int u,v;
			u=read();v=read();
			add(0,u,v);
			add(1,v,u);
			du[0][v]++;
			du[1][u]++;
		}
		topo(0);
		topo(1);
		for(int i=1;i<=n;i++)
			add(1,0,n,dis[1][i]);
		for(int x=1;x<=n;x++)
		{
			for(int i=head[1][change[x]];i;i=e[1][i].nxt)
			{
				del(1,0,n,dis[0][e[1][i].v]+dis[1][change[x]]+1);
			}
			del(1,0,n,dis[1][change[x]]);
			if(res[1]<ans||(ans==res[1]&&change[x]<ansx))
			{
				ansx=change[x];
				ans=res[1];
			}
			for(int i=head[0][change[x]];i;i=e[0][i].nxt)
			{
				add(1,0,n,dis[0][change[x]]+dis[1][e[0][i].v]+1);
			}
			add(1,0,n,dis[0][change[x]]);
		}
		printf("%d %d
",ansx,ans);
	}
	return 0;
}
/*
1
6 5
1 3
1 4
3 6
3 4
4 5
*/

T2 贝尔数

暴力处理前50项贝尔数,把 (mod) 拆分成5个小质数的积。
矩阵乘法快速算出五个小质数下的答案,中国剩余定理合并答案。

[egin{vmatrix} 0& 0& 0& 0& 0& 1\ 1& 1& 0& 0& 0& 0\ 0& 1& 1& 0& 0& 0\ 0& 0& 1& 1& 0& 0\ …& …& …& …& …& …\ 0&0 &0 &0 &1 &1 end{vmatrix} imes egin{vmatrix} B_1 \ B_2 \ B_3 \ B_4 \ …… \ B_p end{vmatrix} = egin{vmatrix} B_p \ B_{p+1} \ B_{p+2} \ B_{p+3} \ …… \ B_{2p-1} end{vmatrix}]

#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
//#define int long long
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*w;
}
int _min(int a,int b){return a<b?a:b;}
int _max(int a,int b){return a>b?a:b;}
int n,C[60][60][6],mo[6]={0,31,37,41,43,47},mod,B[60][6],ys[6],mi[6],ji=95041567;
long long ans=0;
struct jvzhen
{
	int n,m;
	int s[60][60];
	void build()
	{
		for(int i=1;i<=n;i++)
			s[i][i]=1;
		return;
	}
	void clear()
	{
		memset(s,0,sizeof s);
	}
	void write()
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				printf("%d ",s[i][j]);
			}
			puts("");
		}
	}
	void write01()
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				printf("%d",s[i][j]);
			}
			puts("");
		}
	}
};
jvzhen operator * (jvzhen &a,jvzhen &b)
{
	jvzhen res;
	res.clear();
	res.n=a.m;
	res.m=b.n;
	memset(res.s,0,sizeof res.s);
	for(int i=1;i<=a.n;i++)
	{
		for(int j=1;j<=b.m;j++)
		{
			for(int k=1;k<=a.m;k++)
			{
				res.s[i][j]=((res.s[i][j]+a.s[i][k]*b.s[k][j]%mod)%mod+mod)%mod;
			}
		}
	}
	return res;
}
jvzhen quick_pow(jvzhen a,int b)
{
	jvzhen res;
	res.clear();
	res.n=res.m=a.n;
	res.build();
	while(b)
	{
		if(b&1)
		{
			res=a*res;
		}
		a=a*a;
		b>>=1;
	}
	return res;
}
jvzhen x[6],y[6];
int exgcd (int a,int b ,int& x,int& y) {//函数将返回(gcd(a,b))
    if(b==0)
	{
        x=1,y=0;
        return a;
    }    
    int d=exgcd(b,a%b,y,x);
    y-=(a/b)*x;
    return d;
}
int inv(int a,int b)
{
	int iv,tp;
	exgcd(a,b,iv,tp);
	return (iv%b+b)%b;
}
int main()
{
	freopen("bell.in","r",stdin);
	freopen("bell.out","w",stdout);
	for(int k=1;k<=5;k++)
	{
		mi[k]=ji/mo[k];
		y[k].n=y[k].m=mo[k];
		y[k].s[1][mo[k]]=1;
		for(int i=2;i<=mo[k];i++)
		{
				y[k].s[i][i]=y[k].s[i][i-1]=1;
		}
		//y[k].write01();
	}
	for(int i=1;i<=5;i++)
	{
		C[0][0][i]=1;
	}
	for(int i=1;i<=50;i++)
	{
		for(int j=0;j<=i;j++)
		{
			for(int k=1;k<=5;k++)
			{
				C[i][j][k]=(C[i-1][j][k]+C[i-1][j-1][k])%mo[k];
			}
		}
	}
	for(int o=1;o<=5;o++)
	{
		B[0][o]=1;
		for(int i=0;i<=49;i++)
		{
			for(int k=0;k<=i;k++)
			{
				B[i+1][o]+=C[i][k][o]*B[k][o]%mo[o];
				B[i+1][o]%=mo[o];
			}
		}
	}
	for(int k=1;k<=5;k++)
	{
		x[k].n=mo[k];
		x[k].m=1;
		for(int i=1;i<=mo[k];i++)
		{
			x[k].s[i][1]=B[i][k];
		}
	}
	int T=read();
	while(T--)
	{
		ans=0;
		n=read();
		for(int i=1;i<=5;i++)
		{
			if(n<=50)
				ys[i]=B[n][i];
			else
			{
				int c=ceil(1.0*(n-mo[i])/(mo[i]-1)),gt=(n-mo[i])%(mo[i]-1);
				if(gt==0)	gt=mo[i]-1;
				gt++;
				mod=mo[i];
				//y[i].write01();
				jvzhen tmp=quick_pow(y[i],c);
				//tmp.write01();
				mod=mo[i];
				tmp=tmp*x[i];
				//tmp.write();
				ys[i]=tmp.s[gt][1];
			}
		}
		for(int i=1;i<=5;i++)
		{
			mod=ji;
			//cout<<mi[i]<<" "<<mo[i]<<endl;
			long long tmp=(1LL*mi[i]*ys[i]%ji*inv(mi[i],mo[i])%ji+ji)%ji;
			//cout<<tmp<<endl;
			ans=(ans+tmp)%ji;
		}
		printf("%lld
",ans);
	}
	return 0;
}

T3 穿越广场

AC自动机上DP,(f_{l,r,k,typ}) 表示匹配了长度 (l)(r)个R,匹配到AC自动机 (k) 节点,状态为包含了串 (0,1,2,12)

#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
//#define int long long
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*w;
}
int _min(int a,int b){return a<b?a:b;}
int _max(int a,int b){return a>b?a:b;}
const int N=220,mod=1e9+7;
int m,n,f[N][N][N][4],ans;
char c[N];
namespace AC_zdj
{
	int tot;
	struct AC_zdj
	{
		int son[2],num,fail;//0R 1D
	}AC[N];
	int change(char x)
	{
		if(x=='R')
			return 0;
		else
			return 1;
	}
	void Build(char *s,int ys)
	{
		int len=strlen(s+1),p=0;
		for(int i=1,gg;i<=len;i++)
		{
			gg=change(s[i]);
			if(!AC[p].son[gg])
				AC[p].son[gg]=++tot;
			p=AC[p].son[gg];
		}
		AC[p].num|=ys;
		return;
	}
	void get_fail()
	{
		AC[0].fail=0;
		queue<int>q;
		for(int i=0;i<2;i++)
		{
			if(AC[0].son[i])
			{
				AC[AC[0].son[i]].fail=0;
				q.push(AC[0].son[i]);
			}
		}
		while(!q.empty())
		{
			int u=q.front();q.pop();
			for(int i=0;i<2;i++)
			{
				if(AC[u].son[i])
				{
					AC[AC[u].son[i]].fail=AC[AC[u].fail].son[i];
					AC[AC[u].son[i]].num|=AC[AC[AC[u].son[i]].fail].num;
					q.push(AC[u].son[i]);
				}
				else
					AC[u].son[i]=AC[AC[u].fail].son[i];
			}
		}
	}
	void clear()
	{
		memset(AC,0,sizeof AC);
		tot=0;
	}
};
using namespace AC_zdj;
int main()
{
	freopen("square.in","r",stdin);
	freopen("square.out","w",stdout);
	int T=read();
	while(T--)
	{
		m=read();n=read();
		scanf("%s",c+1);
		Build(c,1);
		scanf("%s",c+1);
		Build(c,2);
		get_fail();
		f[0][0][0][0]=1;
		for(int l=0;l<m+n;l++)
		{
			for(int r=0;r<=_min(l,m);r++)
			{
				for(int k=0;k<=tot;k++)
				{
					for(int typ=0;typ<4;typ++)
					{
						f[l+1][r+1][AC[k].son[0]][typ|AC[AC[k].son[0]].num]+=f[l][r][k][typ];
						f[l+1][r+1][AC[k].son[0]][typ|AC[AC[k].son[0]].num]%=mod;
						f[l+1][r][AC[k].son[1]][typ|AC[AC[k].son[1]].num]+=f[l][r][k][typ];
						f[l+1][r][AC[k].son[1]][typ|AC[AC[k].son[1]].num]%=mod;
					}
				}
			}
		}
		/*
		for(int l=0;l<=m+n;l++)
		{
			for(int r=0;r<=_min(l,m);r++)
			{
				for(int k=0;k<=tot;k++)
				{
					for(int typ=0;typ<4;typ++)
					{
					//	printf("%d %d %d %d:%d
",l,r,k,typ,f[l][r][k][typ]);
					}
				}
			}
		}*/
		ans=0;
		for(int i=0;i<=tot;i++)
		{
			ans+=f[n+m][m][i][3];
			ans%=mod;
		}
		printf("%d
",ans);
		clear();
		memset(f,0,sizeof f);
		memset(c,0,sizeof c);
	}
	return 0;
}

T4 舞动的夜晚

最大匹配跑完以后,对于有流量的边反向见图,没有的正向见图跑Tarjan强连通分量。一个分量内的或者匹配边两边端点的就不在答案内。其他的在。

#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
//#define int long long
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*w;
}
int _min(int a,int b){return a<b?a:b;}
int _max(int a,int b){return a>b?a:b;}
const int N=110000,M=1100000,INF=0x7fffffff;
int n,m,T,s,t,xs,xt,dep[N],cnt=1,head[N],cur[N],zhan[N],top,belong[N],dfn[N],low[N],st,scc,ans; 
vector<int>b[N];
bool inq[N],vis[M];
queue<int>q;
struct edge
{
	int v,nxt,w,u;
}e[M];
void add(int u,int v,int w)
{
	e[++cnt].v=v;
	e[cnt].u=u;
	e[cnt].nxt=head[u];
	e[cnt].w=w;
	head[u]=cnt;
}
void make(int u,int v)
{
	add(u,v,1);
	add(v,u,0);
}
bool SPFA()
{
	q.push(xs);
	for(int i=1;i<=t;i++)
		dep[i]=INF,cur[i]=head[i];
	dep[xs]=0;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=head[u],v;i;i=e[i].nxt)
		{
			v=e[i].v;
			if(dep[v]>dep[u]+1&&e[i].w>0)
			{
				dep[v]=dep[u]+1;
				if(!inq[v])
					q.push(v);
			}
		}
	}
	return dep[xt]!=INF;
}
int dfs(int u,int minn)
{
	if(u==xt)
	{
		ans+=minn;
		return minn;
	}
	int used=0;
	for(int i=cur[u],v;i;i=e[i].nxt)
	{
		cur[u]=i;
		v=e[i].v;
		if(dep[v]==dep[u]+1&&e[i].w>0)
		{
			int tmp=dfs(v,_min(minn,e[i].w));
			if(tmp>0)
			{
				used+=tmp;
				e[i].w-=tmp;
				e[i^1].w+=tmp;
				if(used==minn)
					break;
			}
		}
	}
	return used;
}
void Dinic()
{
	while(SPFA())
	{
		dfs(xs,INF);
	}
}
void Tarjan(int cur)
{
    dfn[cur]=low[cur]=++st;
    zhan[++top]=cur;inq[cur]=true;
    for(auto v:b[cur])
    {
        if(dfn[v]==0)
        {
            Tarjan(v);
            low[cur]=_min(low[cur],low[v]);
        }
        else
        {
            if(inq[v]==true)
            {
                low[cur]=min(low[cur],dfn[v]);
            }
        }
    }
    if(low[cur]==dfn[cur])
    {
        scc++;
        int ding;
        do
        {
            ding=zhan[top];
            inq[ding]=false;
            zhan[top--]=0;
            belong[ding]=scc;
        }while(ding!=cur);
    }
    return;
}
int main()
{
	freopen("night.in","r",stdin);
	freopen("night.out","w",stdout);
	n=read();m=read();T=read();
	s=n+m+1;t=s+1;
	for(int i=1,u,v;i<=T;i++)
	{
		u=read();v=read();
		make(u,v+n);
	}
	for(int i=1;i<=n;i++)
		make(s,i);
	for(int i=1;i<=m;i++)
		make(i+n,t);
	xs=s;xt=t;
	Dinic();
	for(int i=2,u,v;i<=cnt;i++)
	{
		if(e[i].w)
		{
			u=e[i].u;v=e[i].v;
			b[u].push_back(v);
			//printf("%d %d
",u,v);
		}
	}
	for(int i=1;i<=n+m+2;i++)
	{
		if(!dfn[i])
			Tarjan(i);
	}
	for(int i=3,u,v;i<=cnt;i+=2)
	{
		u=e[i].u;
		v=e[i].v;
		if(belong[u]==belong[v]||e[i].w>0)
		{
			vis[i]=1;
		}
	}
	ans=0;
	for(int i=1;i<=T;i++)
	{
		if(!vis[i*2+1])
			ans++;
	}
	printf("%d
",ans);
	for(int i=1;i<=T;i++)
	{
		if(!vis[i*2+1])
			printf("%d ",i);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/HKHbest/p/15331077.html