雅礼培训1.2

7-20省选组(雅礼培训2018-1-2)

T1 串

T1

  • 无法取完的三种情况:
    1 , 1, 1形如 a a a a a a a a aaaaaaaa aaaaaaaa
    2 , 2, 2形如 a a a b a a a aaabaaa aaabaaa
    3 , 3, 3形如 a b a b a b a abababa abababa
  • 若不是回文串输出 1 1 1
  • 若是回文串输出 2 2 2
  • 为什么不可能操作三次或以上:
    反证法。假设需要操作至少三次,则必有至少两个回文前缀,它们的对称轴位置不一样,利用这两个对称轴可以使很多位置的字符相等,最后只能出现以上无法取完的三种情况,矛盾。
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=a;i<=b;i++)
#define For(i,a,b) for (register int i=a;i>=b;i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const int N=2e5+5;
int T,n,check,ans[N];
char s[N];
int read()
{
	int x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
int HW(int l,int r)
{
	FOR(i,l,(l+r)>>1)
		if (s[i]!=s[r+l-i]) return 0;
	return 1;
}
int No()
{
	int hw=HW(1,n);
	int c1=1,c2=0,c3=0,tmp=0;
	FOR(i,2,n) if (s[i]!=s[1]) c1=0;
	if (hw)
	{
		c3=1;
		FOR(i,1,n) if (s[i]==s[1]) tmp++;
		if (tmp==n-1&&n%2==1&&s[(n+1)/2]!=s[1]) c2=1;
		FOR(i,1,n)
		{
			if (i%2==1&&s[i]!=s[1]) c3=0;
			if (i%2==0&&s[i]!=s[2]) c3=0;
		}
	}
	return c1||c2||c3;
}
void Solve()
{
	if (No()) ans[++ans[0]]=-1;
	else if (HW(1,n)) ans[++ans[0]]=2;
	else ans[++ans[0]]=1;
	return;
}
int main()
{
//	freopen("testdata.in","r",stdin);
	T=read();
	while (T--)
	{
		n=read();
		scanf("%s",s+1);
		Solve();
	}
	FOR(i,1,ans[0]) printf("%d\n",ans[i]);
	return 0;
}

T2 变量

T2
最小割建模

  • 对于每一个变量 w [ i ] w[i] w[i],连向源点流量 − W -W W,连向汇点流量 W W W(负的流量加上一个正数最后减回来)
  • 对于不带绝对值的贡献直接加在第一种上面
  • 对于带绝对值的贡献,若两变量相等则无贡献,不相等则两倍贡献,所以将两个变量连上流量为两倍贡献的双向边
  • 对于最后三种限制,随便连几个 i n f inf inf的边限制一下
  • 发现 W W W可以提出来,那就少开几个 l o n g l o n g long long longlong最后乘上 W W W
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=a;i<=b;i++)
#define For(i,a,b) for (register int i=a;i>=b;i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define GO(u) for (register int j=first[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const int N=2e5+5;
const ll inf=1e18;
int t,n,W,p,q,x,y,z,ai,bi,ci,di,ei,fi,r,mx;
int val[N],v[1010][1010];
int tot=1,first[N],nxt[N<<1];
int S,T,mincut,flow,depth[N];
ll ans[N];
queue <int> Q;
struct E
{
	int u,v;
	ll flow;
}e[N<<1];
inline void Add(int u,int v,ll flow)
{
	tot++;
	nxt[tot]=first[u];
	first[u]=tot;
	e[tot]=(E){u,v,flow};
	return;
}
inline void Addedge(int u,int v,ll flow)
{
	Add(u,v,flow);
	Add(v,u,0);
	return;
}
inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
inline void Init()
{
	mincut=0;
	mx=-1;
	tot=1;
	mem(first,-1);
	mem(val,0);
	mem(v,0);
	FOR(i,1,n) val[i]=1;
	return;
}
inline int BFS()
{
	while (Q.size()) Q.pop();
	mem(depth,0);
	depth[S]=1;
	Q.push(S);
	while (Q.size())
	{
		int tmp=Q.front();
		Q.pop();
		GO(tmp)
		{
			int v=e[j].v;
			if (!e[j].flow) continue;
			if (depth[v]) continue;
			depth[v]=depth[tmp]+1;
			Q.push(v);
		}
	}
	if (depth[T]) return 1;
	else return 0;
}
inline ll Dinic(int u,ll f)
{
	if (u==T) return f;
	ll rest=f,k;
	GO(u)
	{
		int v=e[j].v;
		if (!e[j].flow) continue;
		if (depth[v]!=depth[u]+1) continue;
		k=Dinic(v,min(rest,e[j].flow));
		if (!k) continue;
		e[j].flow-=k;
		e[j^1].flow+=k;
		rest-=k;
	}
	return f-rest;
}
inline void Check_line()
{
	for (int i=2;i<=tot;i+=2) printf("%d %d %lld\n",e[i].u,e[i].v,e[i].flow);
	return;
}
ll bz[N];
inline void Check_Ans()
{
	FOR(i,1,ans[0]) bz[i]=read();
	FOR(i,1,ans[0]) printf("%lld %lld %d\n",ans[i],bz[i],(ans[i]==bz[i]));
	return;
}
int main()
{
//	freopen("variable1.in","r",stdin);
//	freopen("myans.out","w",stdout);
	t=read();
	while (t--)
	{
		
		n=read(),W=read(),p=read(),q=read();
		Init();
		S=n+1,T=n+2;
		FOR(i,1,p)
		{
			x=read(),y=read(),z=read(),ai=read(),bi=read(),ci=read(),di=read(),ei=read(),fi=read();
			val[x]+=di-fi;
			val[y]+=ei-di;
			val[z]+=fi-ei;
			v[min(x,y)][max(x,y)]+=2*ai;
			v[min(y,z)][max(y,z)]+=2*bi;
			v[min(x,z)][max(z,x)]+=2*ci;
		}
		FOR(i,1,n) mx=max(mx,val[i]);
		mx++;
		FOR(i,1,n)
		{
			Addedge(S,i,mx-val[i]);
			Addedge(i,T,mx+val[i]);
		}
		FOR(i,1,n-1)
			FOR(j,i+1,n) if (v[i][j]) Addedge(i,j,v[i][j]),Addedge(j,i,v[i][j]);
		FOR(i,1,q)
		{
			x=read(),y=read(),r=read();
			switch (r)
			{
				case 0:
					Addedge(x,y,inf);
					break;
				case 1:
					Addedge(x,y,inf);
					Addedge(y,x,inf);
					break;
				case 2:
					Addedge(x,T,inf);
					Addedge(S,y,inf);
					break;
			}
		}
	//	Check_line();
		while (BFS())
			if ((flow=Dinic(S,inf))) mincut+=flow;
		ans[++ans[0]]=(1LL*mincut-n*mx)*W;
	}
//	Check_Ans();
	FOR(i,1,ans[0]) printf("%lld\n",ans[i]);
	return 0;
}

T3 取石子

T3
每堆石子对于 ( a + b ) (a+b) (a+b)取模
假设 a &lt; b a &lt; b a<b
然后分以下四种情况讨论

  • c a s e 1 : case 1: case1: x &lt; a &lt; b x&lt;a&lt;b x<a<b 两个人都不能取,这堆石头没有实际作用,计数的时候统计上即可
  • c a s e 2 : case 2: case2: a ≤ x &lt; b a \leq x&lt;b ax<b 只有A能取,这种石头只要存在则A必胜
  • c a s e 3 : case 3: case3: b ≤ x &lt; 2 ∗ a b \leq x&lt;2*a bx<2a 两个人都能取,并且只能取一次,胜负和奇偶有关
  • c a s e 4 : case 4: case4: b ≤ x b \leq x bx , 2 ∗ a ≤ x 2*a \leq x 2ax 两个人都能取,但是B只能取一次,A可以取多次

结论如下:

  • 存在 c a s e 2 case 2 case2 则A必胜
  • 存在两个或以上 c a s e 4 case 4 case4 则A必胜
  • 存在一个 c a s e 4 case 4 case4 和奇数个 c a s e 3 case 3 case3 ,先手必胜
  • 存在一个 c a s e 4 case 4 case4 和偶数个 c a s e 3 case 3 case3, A必胜
  • 存在奇数/偶数个 c a s e 3 case 3 case3,先手/后手必胜
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int mod=1e9+7;
ll n,a,b,x[N],cnt1=0,cnt2=0,cnt3=0,cnt4=0,mn,mx,ans1=0,ans2=0,ans3=0,ans4=0;
ll read()
{
	ll x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
ll qpow(ll A,ll B)
{
	ll ret=1;
	while (B)
	{
		if (B&1) ret=ret*A%mod;
		B>>=1;
		A=A*A%mod;
	}
	return ret;
}
void Solve()
{
	ans1=(ans1+(qpow(2,cnt2)-1)*qpow(2,n-cnt2)%mod)%mod;//存在case 2 
	if (cnt4>=2) ans1=(ans1+(qpow(2,cnt4)-1-cnt4)*qpow(2,cnt1+cnt3)%mod)%mod;//两个 case 4 
	if (cnt4)// 一个case 4 
	{
		//讨论case 3奇偶 
		if (cnt3) ans1=(ans1+qpow(2,cnt1+cnt3-1)*cnt4%mod)%mod,ans3=(ans3+qpow(2,cnt1+cnt3-1)*cnt4%mod)%mod;//case 3大于等于1是奇偶对半分,必定是偶数(qpow(2,cnt3)) 
		else ans3=(ans3+qpow(2,cnt1)*cnt4%mod)%mod;
	}
	if (cnt3) ans3=(ans3+qpow(2,cnt3+cnt1-1)%mod)%mod,ans4=(ans4+qpow(2,cnt3+cnt1-1)%mod)%mod;//没有cacse 4,讨论case 3奇偶
	else if (cnt1) ans4=(ans4+qpow(2,cnt1))%mod;
	return;
}
int main()
{
	n=read(),a=read(),b=read();
	FOR(i,1,n) x[i]=read()%(a+b);
	mn=min(a,b);
	mx=max(a,b);
	FOR(i,1,n)
	{
		if (x[i]<mn) cnt1++;
		if (mn<=x[i]&&x[i]<mx) cnt2++;
		if (x[i]>=mx&&x[i]<2*mn) cnt3++;
		if (x[i]>=mx&&x[i]>=2*mn) cnt4++;
	}
	Solve();
	if (a>b) swap(ans1,ans2);
	printf("%lld %lld %lld %lld\n",ans1,ans2,ans3,ans4);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值