码迷,mamicode.com
首页 > 其他好文 > 详细

AtCoder Grand Contest 045

时间:2020-07-06 12:41:42      阅读:88      评论:0      收藏:0      [点我收藏+]

标签:printf   namespace   转化   linear   oid   做了   clear   math   flag   

Preface

这场比赛真的是鸽了太久了的说,一来题挺难的,二来中间因为ZJOI和市统测占用了不少时间

所以题目都记不太得了随便胡一下吧

PS:太菜了所以只做了ABCD,其中BCD都是看一半题解才会的菜哭


A - Xor Battle

首先肯定考虑倒着做,我们维护\(0\)玩家能获胜的集合\(S\),考虑从后往前判断:

  • 当前为\(0\)玩家的回合,那么\(S‘=S\cup\{x\operatorname{xor} a_i,x\in S\}\)
  • 当前为\(1\)玩家的回合,那么若\(a_i\in S\),则\(S‘=S\);否则\(S‘=\emptyset\)

为什么在\(1\)玩家的回合我们可以这么做?因为考虑\(0\)玩家的回合时我们相当于维护了一个线性基

\(a_i\in S\)那么无论哪个数\(\operatorname{xor} a_i\)都始终在线性基内,那么必输

否则它随便异或上一个数都不在\(S\)中(考虑异或的性质),那么必胜

所以直接线性基维护即可

#include<cstdio>
#define RI register int
using namespace std;
typedef long long LL;
const int N=205;
struct Linear_Basis
{
	LL p[63];
	inline void clear(void)
	{
		for (RI i=0;i<63;++i) p[i]=0;
	}
	inline void insert(LL x)
	{
		for (RI i=62;~i;--i) if ((x>>i)&1)
		{
			if (!p[i]) return (void)(p[i]=x); x^=p[i];
		}
	}
	inline bool exist(LL x)
	{
		for (RI i=62;~i;--i) if ((x^p[i])<x) x^=p[i]; return !x;
	}
}l;
int t,n; LL a[N]; char s[N];
int main()
{
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%lld",&a[i]);
		scanf("%s",s+1); if (s[n]==‘1‘) { puts("1"); continue; }
		bool flag=0; for (l.clear(),i=n;i;--i) if (s[i]==‘1‘)
		{
			if (!l.exist(a[i])) { flag=1; break; }
		} else l.insert(a[i]);
		puts(flag?"1":"0");
	}
	return 0;
}


B - 01 Unbalanced

首先考虑转化问题,把\(0\)看作\(-1\)\(1\)看作\(1\),然后一个区间的贡献就是区间和的绝对值

转化一下我们发现只要求出前缀和\(pre_i\)\(pre\)的极差就是最大贡献,所以我们要最小化极差

然后很naive想着随便枚举一下久好了,但是一个顺序问题怎么都搞不来,直接GG

看了题解,由于这里有两个border,所以我们卡死一维再优化另一个

考虑枚举\(pre\)\(\min\)\(l\),那么现在我们要保证\(pre_i\ge l\)的情况下最小化最大值

首先我们考虑先把?全填成\(1\),然后贪心地从前往后改,考虑是否把\(1\)改成\(0\)(因为改后面的一定不会比前面优),并保证\(pre_i\ge l\)

然后就有了一个\(O(n^2)\)的做法,设\(\min\{pre_i\}=M\),枚举\(l=M,M-1,\cdots 0\)

观察贪心的过程,容易发现当\(l=M-2\)时的答案一定不会优于\(l=M\)时的答案,\(l=M-3\)同理

因此只用考虑\(l=M\)\(l=M-1\)的情况即可

#include<cstdio>
#include<iostream> 
#define RI register int
#define CI const int&
using namespace std;
const int N=5005,mod=1e9+7;
int n,a,b,f[N][2],g[N],dp[N][2],ans;
inline void inc(int& x,CI y)
{
	if ((x+=y)>=mod) x-=mod;
}
inline int sum(CI x,CI y)
{
	int t=x+y; return t>=mod?t-mod:t;
}
inline int sub(CI x,CI y)
{
	int t=x-y; return t<0?t+mod:t;
}
inline int quick_pow(int x,int p,int mul=1)
{
	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
int main()
{
	RI i,j; scanf("%d%d%d",&n,&a,&b); if (a>b) swap(a,b);
	if (b==1) return printf("%d",quick_pow(2,n)),0;
	for (f[0][0]=f[0][1]=i=1;i<=n;++i) for (j=1;j<=i;++j)
	{
		if (j>=a) inc(f[i][0],f[i-j][1]); inc(f[i][1],f[i-j][0]);
	}
	for (g[0]=i=1;i<=n;++i) g[i]=sum(f[i][0],f[i][1]);
	for (i=1;i<n;++i) 
	{
		if (i<a) dp[i][0]=1; for (j=1;j<min(i,a);++j) inc(dp[i][0],dp[i-j][1]);
		if (i<b) dp[i][1]=g[i-1]; for (j=1;j<min(i,b);++j)
		inc(dp[i][1],1LL*dp[i-j][0]*(j<=2?1:g[j-2])%mod);
		if (n-i<a) inc(ans,dp[i][1]); if (n-i<b) inc(ans,1LL*dp[i][0]*g[n-i-1]%mod);
	}
	return printf("%d",sub(quick_pow(2,n),ans)),0;
}

AtCoder Grand Contest 045

标签:printf   namespace   转化   linear   oid   做了   clear   math   flag   

原文地址:https://www.cnblogs.com/cjjsb/p/13254162.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!