Codeforces Deltix Round Summer 2021 [Div.1 + Div.2]简要题解

A:A Variety of Operations

根据题意随便判一判即可。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;scanf("%d",&t);
	while(t--)
	{
		int c,d;scanf("%d%d",&c,&d);
		if((c+d)&1)puts("-1");
		else if(c==0&&d==0)puts("0");
		else if(c==d)puts("1");
		else puts("2");
	}
	return 0;
}

B:Take Your Places!

这里只考虑\(n\) 为偶数的情况,\(n\) 为奇数类似。那么有解当且仅当奇数出现\(\dfrac n2\) 次,而且要么全部在下标为奇数的位置上,要么全部在下标为偶数的位置上。分别求出答案取最小值。多测小心因为中途continue之后没有清空数组哦。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,a[N];vector<int>p;
int main()
{
	int t;scanf("%d",&t);
	while(t--)
	{
		p.clear();
		scanf("%d",&n);int ct=0;
		for(int i=1;i<=n;++i)
		{
			scanf("%d",&a[i]);
			if(a[i]&1)++ct,p.push_back(i);
		}
		if(!(n&1))
		{
			if(ct*2!=n){puts("-1");continue;}
			ll ans=0;
			for(int i=1,j=0;i<=n;i+=2,++j)ans+=abs(i-p[j]);
			ll res=0;
			for(int i=2,j=0;i<=n;i+=2,++j)res+=abs(i-p[j]);
			ans=min(ans,res);
			printf("%lld\n",ans);
		}
		else
		{
			if(ct!=n/2&&ct!=n/2+1){puts("-1");continue;}
			ll ans=0;
			if(ct==n/2)
				for(int i=2,j=0;i<=n;i+=2,++j)ans+=abs(i-p[j]);
			else
				for(int i=1,j=0;i<=n;i+=2,++j)ans+=abs(i-p[j]);
			printf("%lld\n",ans);
		}
	}
	return 0;
}

C:Compressed Bracket Sequence

将左括号看作向上走一步,右括号看作向下走一步,那么括号序列合法当且仅当依次遍历后回到原位置并且任何时刻都在原位置之上。因此直接枚举左右端点所在位置,维护最低点以及最终位置即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1005;
const ll inf=1e15;
int n,a[N];ll ans;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d",a+i);
	for(int i=1;i<=n;++i)
	{
		if(!(i&1))continue;
		ll dep=inf,las=0;
		for(int j=i+1;j<=n;++j)
		{
			if(!(j&1))
			{
				ll mt=max(1ll,-dep),op=las+mt;
				ans+=max(0ll,min(a[i]-mt+1,a[j]-op+1));
			}
			int tp=(j&1)?1:-1;
			las+=tp*a[j];dep=min(dep,las);
		}
	}
	printf("%lld\n",ans);
	return 0;
}

D:Take a Guess

关键性质:\(a+b=(a\&b)+(a\mid b)\) 。注意\(a+b\) 可能会爆int。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e4+5;
int n,k;ll a[N];
inline ll sum(int x,int y)
{
	ll tt,res=0;
	printf("and %d %d\n",x,y);
	fflush(stdout);scanf("%lld",&tt);res=tt;
	printf("or %d %d\n",x,y);
	fflush(stdout);scanf("%lld",&tt);res+=tt;
	return res;
}
int main()
{
	scanf("%d%d",&n,&k);
	ll s1=sum(1,2),s2=sum(2,3),s3=sum(1,3);
	a[1]=(s1+s2+s3)/2-s2;a[2]=s1-a[1];a[3]=s3-a[1];
	for(int i=4;i<=n;++i)a[i]=sum(1,i)-a[1];
	nth_element(a+1,a+k,a+n+1);
	printf("finish %lld\n",a[k]);
	return 0;
}

E:Equilibrium

首先令数组\(c=b-a\) .手模以下样例,发现可以将正数看作左括号连续出现次数,负数看作右括号连续出现次数。那么是否有解等价于括号序列是否合法,而答案等于最深的嵌套层数。可以使用类似C题的思路,使用ST表维护区间最值即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,q,a[N],lg[N];ll s[N],st1[20][N],st2[20][N];
inline ll gmax(int l,int r)
{
	int len=lg[r-l+1];
	return max(st1[len][l],st1[len][r-(1<<len)+1]);
}
inline ll gmin(int l,int r)
{
	int len=lg[r-l+1];
	return min(st2[len][l],st2[len][r-(1<<len)+1]);
}
int main()
{
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;++i)scanf("%d",a+i),a[i]=-a[i];
	for(int i=1,x;i<=n;++i)scanf("%d",&x),a[i]+=x;
	for(int i=1;i<=n;++i)s[i]=s[i-1]+a[i],st1[0][i]=st2[0][i]=s[i];
	lg[1]=0;for(int i=2;i<=n;++i)lg[i]=lg[i>>1]+1; 
	for(int i=1;i<=lg[n];++i)
		for(int j=1;j+(1<<i)-1<=n;++j)
			st1[i][j]=max(st1[i-1][j],st1[i-1][j+(1<<(i-1))]),
			st2[i][j]=min(st2[i-1][j],st2[i-1][j+(1<<(i-1))]);
	while(q--)
	{
		int l,r;scanf("%d%d",&l,&r);
		if(s[r]-s[l-1]!=0)puts("-1");
		else if(-s[l-1]+gmin(l,r)<0)puts("-1");
		else printf("%lld\n",-s[l-1]+gmax(l,r));
	}
	return 0;
}

F:Sports Betting

设全部队的集合为\(All\)

回到期望的定义可知

\[ans=\sum_SF(S)\cdot|S| \]

其中\(F(S)\) 代表\(S\) 集合中全部是winner的概率。\(F(S)\) 可以通过容斥求得:

\[F(S)=G(S,All\setminus S)-\sum_{T\subset S}F(T)\cdot G(S\setminus T,All\setminus S) \]

其中\(G(S,T)=\prod _{u\in S}\prod_{v\in T}\frac {a_u}{a_u+a_v}\) ,即\(S\) 集合完全打败\(T\) 集合的概率。

\(n\) 很小时应该考虑指数级做法。另外考虑概率时不要重复计算或漏掉计算某一事物的概率。

#include<bits/stdc++.h>
using namespace std;
const int N=15,mod=1e9+7;
inline int qpow(int x,int y)
{
	int res=1;
	for(;y;y>>=1,x=1ll*x*x%mod)
		if(y&1)res=1ll*res*x%mod;
	return res;
}
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline void inc(int&x,int y){x=add(x,y);}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline void rec(int&x,int y){x=dec(x,y);}
inline int lb(int x){return x&(-x);}
int n,a[N],pob[N][N],lg[1<<N],res;
int H[1<<N],F[1<<N];
int main()
{
	scanf("%d",&n);
	for(int i=1,j=0;j<n;i<<=1,++j)lg[i]=j;
	for(int i=0;i<n;++i)scanf("%d",a+i);
	for(int i=0;i<n;++i)
		for(int j=0;j<n;++j)
			if(i^j)pob[i][j]=1ll*a[i]*qpow(a[i]+a[j],mod-2)%mod;
	int st=1<<n,All=st-1;
	for(int j=1;j<st;++j)
	{
		int k=All^j,ret=1,u=j,v;
		while(u)
		{
			int now=lg[lb(u)];u-=lb(u);v=k;
			while(v)ret=1ll*ret*pob[now][lg[lb(v)]]%mod,v-=lb(v);
		}
		H[j]=ret;
	}
	for(int i=1;i<st;++i)
	{
		int ans=H[i],sub=(st-1)^i;
		for(int j=(i-1)&i;j;j=(j-1)&i)
		{
			int k=All^i,ret=1,u=j,v;
			while(u)
			{
				int now=lg[lb(u)];u-=lb(u);v=k;
				while(v)ret=1ll*ret*pob[now][lg[lb(v)]]%mod,v-=lb(v);
			}
			rec(ans,1ll*F[i^j]*ret%mod);
		}
		F[i]=ans;
		inc(res,1ll*F[i]*__builtin_popcount(i)%mod);
	}
	printf("%d\n",res);
	return 0;
}
posted @ 2021-08-30 21:29  BILL666  阅读(58)  评论(2编辑  收藏  举报