2018.12.1 Test


2018.12.1 Test

题目为2018.1.2雅礼集训。

时间:3.5h
期望得分:100+30+10
实际得分:100(0)+0+10

A 串string(思路)

如果一个串不是回文串,答案是1(我竟然漏了QAQ)。
否则,除了以下三种情况无解外,都能两次消掉:
aaaaa aabaa ababa
判一下就OK了。

#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=1e5+5;

char s[N];

inline int read()
{
	int now=0,f=1;register char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now*f;
}
bool Check0(int n)
{
	int mid=n>>1;
	for(int i=1; i<=mid; ++i) if(s[i]!=s[n-i+1]) return puts("1"),0;
	return 1;
}
bool Check1(int n)//All the same
{
	const char c=s[1];
	for(int i=2; i<=n; ++i) if(s[i]!=c) return 1;
	puts("-1");
	return 0;
}
bool Check2(int n)
{
	if(!(n&1)) return 1;
	const char c1=s[1],c2=s[2];
	for(int i=3; i<n; i+=2) if(s[i]!=c1||s[i+1]!=c2) return 1;
	if(s[n]!=c1) return 1;
	puts("-1");
	return 0;
}
bool Check3(int n)
{
	if(!(n&1)) return 1;
	s[(n+1)>>1]=s[1];
	return Check1(n);
}

int main()
{
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);

	for(int T=read(); T--; )
	{
		int n=read(); scanf("%s",s+1);
		if(Check0(n)&&Check1(n)&&Check2(n)&&Check3(n)) puts("2");
	}
	return 0;
}

B 变量variable(最小割ISAP)

题目链接

我们发现一个点如果与它相邻的点取值不同,会造成一个系数*(2W)的代价。
想到网络流就好办了。。

比较显然的是拆点,然后建图跑最小费用最大流。但是这样对于限制(aleq b,bleq c),有(aleq c)这种传递性,我好像不会判/连边 QAQ。只会暴力搞但也不想写...

费用流做法里的流量其实没啥用,还是直接考虑最大流/最小割。
这样的话就不用拆点了,每个点向(S)连容量(即权值)为(W)的边,向(T)连容量(-W)的边,就可以了QAQ。那些(系数和*w_i)的代价也加到这两条边上(记它为(x))。为了避免负边可以先让(Ans)减去(|x|),然后根据(x)的正负确定连边(边权都加个(|x|)就消掉负边啦)。
对于代价(a_i|w_x-w_y|),在(x,y)间连容量为(a_i*2W)的双向边((w_x,w_y)取值不同就会加上这个值)。
对于限制,(w_xleq w_y)就由(x)(y)连一条容量(INF)的单向边((x)(W)(y)不能选(-W));(w_x=w_y)就连一条(x)(y)的双向边,容量同样为(INF)(w_x<w_y)就由(x)(T)(INF)边,(S)(y)(INF)边好了(只能(x)取负(y)取正)。

另外边权可以都除个(W),最后再乘个(W)

#include <queue>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=507,M=12000;
const int INF=1e9;

int src,des,coef[N],cur[N],H[N],Enum,fr[M],to[M],nxt[M],cap[M],pre[N],lev[N];

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}

inline void AE(int u,int v,int w,int w2)
{
	to[++Enum]=v, fr[Enum]=u, nxt[Enum]=H[u], H[u]=Enum, cap[Enum]=w;
	to[++Enum]=u, fr[Enum]=v, nxt[Enum]=H[v], H[v]=Enum, cap[Enum]=w2;
}
bool BFS()
{
	static int q[N];
	for(int i=src; i<des; ++i) lev[i]=des+1;
	int h=0,t=1; lev[des]=0, q[0]=des;
	while(h<t)
	{
		int x=q[h++];
		for(int i=H[x]; i; i=nxt[i])
			if(cap[i^1] && lev[to[i]]==des+1) lev[to[i]]=lev[x]+1, q[t++]=to[i];
	}
	return lev[src]<=des;
}
inline int Augment()
{
	int mn=123456789;
	for(int i=des; i!=src; i=fr[pre[i]])
		mn=std::min(mn,cap[pre[i]]);
	for(int i=des; i!=src; i=fr[pre[i]])
		cap[pre[i]]-=mn, cap[pre[i]^1]+=mn;
	return mn;
}
int ISAP()
{
	static int num[N];
	if(!BFS()) return 0;
	for(int i=src; i<=des; ++i) cur[i]=H[i],++num[lev[i]];
	int x=src,res=0;
	while(lev[x]<=des)
	{
		if(x==des) x=src,res+=Augment();
		bool can=0;
		for(int i=cur[x]; i; i=nxt[i])
			if(cap[i] && lev[to[i]]==lev[x]-1)
			{
				can=1, cur[x]=i, pre[x=to[i]]=i;
				break;
			}
		if(!can)
		{
			int mn=des;
			for(int i=H[x]; i; i=nxt[i])
				if(cap[i]) mn=std::min(mn,lev[to[i]]);
			if(!--num[lev[x]]) break;
			++num[lev[x]=mn+1], cur[x]=H[x];
			if(x!=src) x=fr[pre[x]];
		}
	}
	return res;
}
void Work()
{
	int n=read(),W=read(),P=read(),Q=read();
//Clear
	Enum=1, memset(H,0,sizeof H);
//Init
	for(int i=1; i<=n; ++i) coef[i]=1;
	for(int i=1,x,y,z,a,b,c,d,e,f; i<=P; ++i)
	{//a:0 b:1 c:2 d:3 e:4 f:5
		x=read(),y=read(),z=read(),a=read(),b=read(),c=read(),d=read(),e=read(),f=read();
		AE(x,y,a<<1,a<<1), AE(y,z,b<<1,b<<1), AE(z,x,c<<1,c<<1);
		coef[x]+=d-f, coef[y]+=e-d, coef[z]+=f-e;
	}
//limit
	src=0, des=n+1;
	for(int i=1,x,y; i<=Q; ++i)
	{
		x=read(),y=read();
		switch(read())
		{
			case 0: AE(x,y,INF,0); break;
			case 1: AE(x,y,INF,INF); break;
			case 2: AE(x,des,INF,0), AE(src,y,INF,0); break;
		}
	}
//AE
	int ans=0;
	for(int i=1; i<=n; ++i)
	{
		ans-=std::abs(coef[i]);
		if(coef[i]>0) AE(i,des,coef[i]<<1,0);
		else AE(src,i,-coef[i]<<1,0);
	}
	ans+=ISAP();
	printf("%I64d
",1ll*ans*W);
}

int main()
{
	freopen("variable.in","r",stdin);
	freopen("variable.out","w",stdout);

	for(int T=read(); T--; Work());
	return 0;
}

C 取石子stone(思路 博弈)

不妨假设(a<b)
每堆石子先对(a+b)取模((≥a+b)时先手取了后手接着取没有影响啊),然后可以分为4种:
((1)) (x_i<a),没用。
((2)) (a≤x_i<b),只要存在则(A)必胜。
((3)) (b≤x_i<2a),只和奇偶性有关。
((4)) (2a≤x_i<a+b (b≤x_i))((4))存在至少(2)个则(A)必胜,存在(1)个且((3))为偶数则先手必胜,存在(1)个且((3))为奇数则(A)必胜,不存在且((3))为奇数则先手必胜,不存在且((3))为偶数则后手必胜。

时间复杂度(O(n))

orz mjt差点想出正解。

#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define mod 1000000007
typedef long long LL;
const int N=1e5+5;

inline int read()
{
	int now=0,f=1;register char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now*f;
}

int main()
{
	static int pw[N];

	freopen("stone.in","r",stdin);
	freopen("stone.out","w",stdout);

	int n=read(),A=read(),B=read();
	bool Flag=0;
	if(A>B) std::swap(A,B), Flag=1;
	int t[5]={0,0,0,0,0},ans[5]={0,0,0,0,0};
	for(int i=1; i<=n; ++i)
	{
		int x=read()%(A+B);
		++t[1+(x>=A)+(x>=B)+(x>=A+A&&x>=B)];//2A<=x<B 就是(2)啊 
	}
	pw[0]=1;
	for(int i=1; i<=n; ++i) pw[i]=pw[i-1]<<1, pw[i]>=mod&&(pw[i]-=mod);
	//其它任选的不要忘统计或者重复统计QAQ 
	ans[1]=(1ll*(pw[t[2]]-1)*pw[t[3]+t[4]]%mod+1ll*(pw[t[4]]-t[4]-1+mod)*pw[t[3]]%mod+1ll*t[4]*(t[3]?pw[t[3]-1]:0)%mod)%mod;
	ans[3]=((t[3]?pw[t[3]-1]:0)+1ll*t[4]*(t[3]?pw[t[3]-1]:1)%mod)%mod;
	ans[4]=t[3]?pw[t[3]-1]:1;
	for(int i=1; i<=4; ++i) ans[i]=1ll*ans[i]*pw[t[1]]%mod;
	if(Flag) std::swap(ans[1],ans[2]);
	for(int i=1; i<=4; ++i) printf("%d ",ans[i]);

	return 0;
}

考试代码

B

写了费用流。然而边都搞好了不会处理限制的传递性TAT
暴力也挂了TAT(for一遍限制不就行了...)

#include <queue>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int INF=1e9;
const LL INFll=0x3f3f3f3f3f3f3f3f;

inline int read()
{
	int now=0,f=1;register char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now*f;
}
namespace Subtask1
{
	const int N=100;
	int w[N],n,W,P,Q,Enum,H[N],nxt[N],to[N],opt[N];
	LL Ans;
	struct Node{
		int x,y,z,a[6];
		inline void Init() {x=read(),y=read(),z=read(); for(int i=0; i<6; ++i) a[i]=read();}
		inline LL Calc()
		{
			int wx=w[x],wy=w[y],wz=w[z];
			return 1ll*a[0]*std::abs(wx-wy)+a[1]*std::abs(wy-wz)+a[2]*std::abs(wz-wx)+a[3]*(wx-wy)+a[4]*(wy-wz)+a[5]*(wz-wx);
		}
	}A[N];
	
	inline void AE(int o,int v,int u)
	{
		if(u<v) std::swap(u,v), o+=3;
		to[++Enum]=v, opt[Enum]=o, nxt[Enum]=H[u], H[u]=Enum;
	}
	void DFS(int x,int sum)
	{
		if(x>n)
		{
			LL ans=0;
			for(int i=1; i<=P; ++i) ans+=A[i].Calc();
//			puts("Now:");
//			for(int i=1; i<=n; ++i) printf("%d ",w[i]); puts("");
//			printf("ans:%I64d sum:%d
",ans,sum);
			Ans=std::min(Ans,ans+sum);
			return;
		}
		int need=0;
		for(int i=H[x]; i; i=nxt[i])
		{
			int equ=0;
			if(!opt[i])
				if(w[to[i]]==-W) equ=-W;
				else ;
			else if(opt[i]==1) equ=w[to[i]];
			else if(opt[i]==2)
				if(w[to[i]]==-W) return;
				else equ=-W;
			else if(opt[i]==3)
				if(w[to[i]]==W) equ=W;
				else ;
			else if(opt[i]==4) equ=w[to[i]];
			else if(opt[i]==5)
				if(w[to[i]]==W) return;
				else equ=W;
//			printf("%d->%d(%d) equ:%d need:%d
",x,to[i],opt[i],equ,need);
			if(!need) need=equ;
			else if(equ&&equ!=need) return;
		}
		if(!need) w[x]=W, DFS(x+1,sum+W), w[x]=-W, DFS(x+1,sum-W);
		else w[x]=need, DFS(x+1,sum+need);
	}
	void Main(int n,int W,int P,int Q)
	{
		Enum=0, memset(H,0,sizeof H);
		Subtask1::n=n, Subtask1::W=W, Subtask1::P=P, Subtask1::Q=Q;
		for(int i=1; i<=P; ++i) A[i].Init();
		for(int i=1; i<=Q; ++i) AE(read(),read(),read());
		Ans=1e15, DFS(1,0), printf("%I64d
",Ans);
	}
}

//-----
const int N=3005,M=1e5;

int src,des,val[N][N],coef[N],dgr[N],cur[N],H[N],Enum,to[M],nxt[M],cap[M];
LL cost[M],dis[N],Cost;
bool ban[N][N],vis[N];
//std::vector<int> b1[N],b2[N],s1[N],s2[N];//

inline void AE(int u,int v,int w,LL c)
{
//	printf("%d->%d cap:%d cost:%I64d
",u,v,w,c);
	++dgr[u];
	to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum, cap[Enum]=w, cost[Enum]=c;
	to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum, cap[Enum]=0, cost[Enum]=-c;
}
bool SPFA()
{
	static std::queue<int> q;
	memset(vis,0,sizeof vis);
	memset(dis,0x3f,sizeof dis);
	dis[src]=0, q.push(src);
	while(!q.empty())
	{
		int x=q.front(); q.pop(), vis[x]=0;
		for(int i=H[x],v; i; i=nxt[i])
			if(cap[i]&&dis[v=to[i]]>dis[x]+cost[i])
				dis[v]=dis[x]+cost[i], !vis[v]&&(q.push(v),vis[v]=1);
	}
	return dis[des]<INFll;
}
bool DFS(int x)
{
	if(x==des) return 1;
	vis[x]=1;
	for(int &i=cur[x]; i; i=nxt[i])
		if(!vis[to[i]]&&cap[i]&&dis[to[i]]==dis[x]+cost[i])
			if(DFS(to[i]))
				return --cap[i],++cap[i^1],Cost+=cost[i],1;
	return 0;
}
LL MCMF()//GG
{
	Cost=0; int flow=0;
	while(SPFA())
	{
		for(int i=src; i<=des; ++i) cur[i]=H[i];
		while(DFS(src)) ++flow;
	}
//	printf("flow:%d ",flow);
	return std::abs(Cost);
}
void Work()
{
	int n=read(),W=read(),P=read(),Q=read();
	if(n<=17) {Subtask1::Main(n,W,P,Q); return;}
//Clear
	Enum=1, memset(H,0,sizeof H);
	memset(dgr,0,sizeof dgr), memset(coef,0,sizeof coef), memset(val,0,sizeof val), memset(ban,0,sizeof ban);
//Init
	for(int i=1,x,y,z,a,b,c,d,e,f; i<=P; ++i)
	{//a:0 b:1 c:2 d:3 e:4 f:5
		x=read(),y=read(),z=read(),a=read(),b=read(),c=read(),d=read(),e=read(),f=read();
		val[x][y]+=a, val[y][x]+=a, val[y][z]+=b, val[z][y]+=b, val[x][z]+=c, val[z][x]+=c;
		coef[x]+=d-f, coef[y]+=e-d, coef[z]+=f-e;
	}
	for(int i=1; i<=n; ++i) ++coef[i];
//	for(int i=1; i<=n; ++i) printf("coef[%d]=%d
",i,coef[i]);
//limit
	int n2=n+n;//0:W n:-W 2n:origin
	for(int i=1; i<=Q; ++i)
	{
		int x=read(),y=read(),opt=read();
		if(x>y) std::swap(x,y), opt+=3;
		switch(opt)
		{
			case 0: ban[x][y+n]=1; break;//x<=y
			case 1: ban[x][y+n]=ban[x+n][y]=1; break;
			case 2: ban[x][y]=ban[x][y+n]=ban[x+n][y+n]=1; break;
			case 3: ban[x+n][y]=1; break;//x>=y
			case 4: ban[x][y+n]=ban[x+n][y]=1; break;
			case 5: ban[x][y]=ban[x+n][y]=ban[x+n][y+n]=1; break;
		}
	}
//AE
	int src=0,des=n+n2+2; ::src=src, ::des=des;
	LL W2=W<<1;
	for(int i=1; i<=n; ++i)
		for(int j=i+1; j<=n; ++j)
			if(val[i][j])
			{
//				printf("val[%d][%d]=%d
",i,j,val[i][j]);
				int x=i,y=j;
				if(!ban[x][y]) AE(x,y,INF,0);
				x=i+n,y=j;
				if(!ban[x][y]) AE(x,y,INF,W2*val[i][j]);
				x=i,y=j+n;
				if(!ban[x][y]) AE(x,y,INF,W2*val[i][j]);
				x=i+n,y=j+n;
				if(!ban[x][y]) AE(x,y,INF,0);
			}
	for(int i=1; i<=n; ++i) AE(src,i+n2,1,0), AE(i+n2,i,1,1ll*coef[i]*W), AE(i+n2,i+n,1,-1ll*coef[i]*W);
	for(int i=1; i<=n; ++i) if(!dgr[i]) AE(i,des,INF,0), AE(i+n,des,INF,0);
//Get_Ans
	printf("%I64d
",MCMF());
}

int main()
{
	freopen("variable.in","r",stdin);
//	freopen("variable.out","w",stdout);

	for(int T=read(); T--; Work());
	return 0;
}

C

(a=b)的10分就是求异或和为0的方案数,只需要求下组合就可以了,但是没想到(orz mjt)抄了zzx的代码(orz zzx)。

#include <cstdio>
#include <cctype>
#include <bitset>
#include <algorithm>
#define gc() getchar()
#define mod 1000000007
typedef long long LL;
const int N=1e5+5;

int Ans[5],X[N],w1[N],w2[N];

inline int read()
{
	int now=0,f=1;register char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now*f;
}
inline int FP(int x,int k)
{
	int t=1;
	for(; k; k>>=1,x=1ll*x*x%mod)
		if(k&1) t=1ll*t*x%mod;
	return t;
}
namespace Subtask3
{//orz zzx
	int n,A[N];
	std::bitset<105>a[32];
	void Gauss(int equ ,int var) {
		int r , c , t ;
		for(r = c = 1;r <= equ && c <= var;++ r ,++ c) {
			t = r;
			for(;t < equ;++ t) if(a[t][c]) break ;
			if(t == equ) {
				-- r ;continue ;
			} else swap(a[t] , a[r]);
			for(int i = r + 1;i <= equ;++ i) if (a[i][c]) a[i] ^= a[r];
		}
		int n = var - r , ans = 1;
		for(int i = 1;i <= n;++ i) {
			ans <<= 1 ;ans %= mod;
		}
		printf("0 0 %d %d
",(FP(2,Subtask3::n)+mod-ans)%mod,ans);
	}
	void Solve(int n,int A)
	{
		Subtask3::n=n;
		for(int i=1; i<=n; ++i)
		{
			int x=read()/A;
			for(int j=1; j<=31; ++j) a[j][i]=x>>j&1;
		}
		Gauss(31,n);
	}
}

int main()
{
//	freopen("stone.in","r",stdin);
//	freopen("stone.out","w",stdout);

	int n=read(),A=read(),B=read();
	if(A==B) return Subtask3::Solve(n,A),0;
	bool Flag=0;
	if(A>B) std::swap(A,B), Flag=1;
	for(int i=1; i<=n; ++i)//写着写着不想写了
	{
		X[i]=read();
		if(X[i]<A) continue;
		if(X[i]>=A&&X[i]<B) {w1[i]=X[i]/A, w2[i]=-w1[i]; continue;}
		int t1=(X[i]-A)%(A+B),t2=(X[i]-B)%(A+B);
		w1[i]=1+t1/A, w2[i]=1+t2/B-t2%B/A;
	}
	printf("%d %d %d %d
",Flag?0:FP(2,n),Flag?FP(2,n):0,0,0);

	return 0;
}
原文地址:https://www.cnblogs.com/SovietPower/p/10051372.html