欢迎来到清街老酒的博客

どんな別れがあったとしても、出会ったことには必ず意味がある

Codeforces Round #668 (Div. 2)

Codeforces Round #668 (Div. 2)

A.Permutation Forgery

题意:给一个数组p,找到另一个数组,使数组中相邻元素相加构成的新数组元素相同。
思路:将数组反着输出。

#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize ("unroll-loops")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
ll t,n,a[1005]; 
int main()
{
	scanf("%lld",&t);
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
		} 
		for(int i=n;i>=1;i--)
		{
			cout<<a[i]<<" ";
		}
		cout<<endl;
	}	
}

B.Array Cancellation

题意:给一个和为0的数组,每次可选择\(a_i\)-1和\(a_j\)+1,若i<j花费为0,否则花费为1,求所有数变为0的花费。
思路:用num存所有数绝对值之和,sum存目前位置可用来与负数免费运算的值,ans存进行免费运算的值。因为每次都是2个数同时运算,所以答案为(num-ans$*$2)/2。

#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize ("unroll-loops")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
ll t,n,sum,a[100005],num,x,ans,s; 
int main()
{
	scanf("%lld",&t);
	while(t--)
	{
		sum=0;ans=0;x=0;num=0;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			if(a[i]>0)
			{
				sum=sum+a[i];
				num+=a[i];
			}
			if(sum>0&&a[i]<0)
			{
				num-=a[i];
				s=-a[i];
				x=min(sum,s);
				sum=sum-x;
				ans=ans+x;
			}
			else if(a[i]<0)
			{
				num-=a[i];
			}
		}
		cout<<(num-2*ans)/2<<endl; 
	}	
}

C.Balanced Bitstring

题意:给一个二进制字符串,其中?能为0或1,问是否能使任意长度为k的字串0,1数量相同。
思路:首先判断同余字符是否相同,不同则输出NO。用a[0]--a[k-1]存储同余位置的字符,若未确定(同余位置全是?)为0,若字符为'0'为1,若字符为'1'为2。再遍历一边字符串,若str[i]为'?',其同余数组a不为0,说明?可以确定,则?变为相应的字符串。遍历同余数组a,若没有a[i]为0,则判断为1和为2数量是否相同,相同YES,反之NO。若有a[i]为0,则为1和为2数量之差小于等于为数量,说明?肯定有一种分配可以使字符串0,1数量相等,则YES,反之则NO。

#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize ("unroll-loops")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
ll t,n,k,a[300005],flag,b[2],sum,len,sum1,sum2; 
//string str;
char str[300005];
int main()
{
	scanf("%lld",&t);
	while(t--)
	{
		memset(a,0,sizeof(a));
		flag=0;
		scanf("%lld%lld",&n,&k);
		//cin>>str;
		scanf("%s",str);
		len=strlen(str);
		for(int i=0;i<len;i++)
		{
			if(str[i]=='?')
			{
				continue;
			}
			else if(a[(i+1)%k]==0)
			{
				a[(i+1)%k]=str[i]-'0'+1;
			}
			else if(a[(i+1)%k]!=0)
			{
				if((str[i]-'0'+1)!=a[(i+1)%k])
				{
					flag=1;
					printf("NO\n");
					break;
				}
			}
		}
		if(flag==0)
		{
		for(int i=0;i<len;i++)
		{
			if(str[i]=='?')
			{
				if(a[(i+1)%k]!=0)
				{
					str[i]=a[(i+1)%k]-1+'0';
				}
			}
		}
		sum=0;sum1=0;sum2=0;
		for(int i=0;i<k;i++)
		{
			if(a[i]==0)
			sum++;
			if(a[i]==1)
			sum1++;
			if(a[i]==2)
			sum2++;
		}
		if(sum)
		{
			if(abs(sum1-sum2)>sum)
			{
					flag=1;
					printf("NO\n");
			}
		}
		else if(sum1!=sum2)
		{
					flag=1;
					printf("NO\n");
		}
		}
		if(flag==0)
		printf("YES\n");
	}	
}

D.Tree Tag

题意:在一颗n个顶点的树上,Alice在a点,Bob在b点,Alice每次可走最多da步,Bob每次最多db步,Alice先走,若无限步内Alice和Bob可占据(每一步的起始,结束点为占据)同个点,Alice胜,反之Bob胜。
思路:Alice获胜有3种可能。
1.Alice一步抓到Bob,即da>\(D_{ab}\),用dfs计算ab距离 \(D_{ab}\)
2.2\(*\)da>\(D_{tree}\) ,即Alice站在树的直径中点可到达树的任何一点。用dfs1算出树的直径。
3.db<2da,即BOb被Alice一直追到极限处,无法越过Alice反向逃跑。

#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize ("unroll-loops")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int t,n,a,b,da,db,ans,mmax,x,flag; 
struct node
{
	int v;
	int next;
}s[200005];
int first[400005],cnt,vis[200005];
void init()
{
	memset(first,0,sizeof(first));
	memset(vis,0,sizeof(vis));
	cnt=1;flag=0;
}
void add(int u,int v)
{
	s[cnt].v=v;
	s[cnt].next=first[u];
	first[u]=cnt++;
}
void dfs(int u,int sum)//计算a,b间距离 
{
	vis[u]=1;
	for(int i=first[u];i;i=s[i].next)
	{
		int v=s[i].v;
		if(vis[v])
		continue;
		if(v==b)
		{
			ans=sum+1;
			flag=1;
			return;
		}
		dfs(v,sum+1);
		if(flag==1)
		return;
	}
}
void dfs1(int u,int sum)
{
	vis[u]=1;
	for(int i=first[u];i;i=s[i].next)
	{
		int v=s[i].v;
		if(vis[v])
		continue;
		dfs1(v,sum+1);
	}	
	if(sum>mmax)
	{
		mmax=sum;
		x=u;
	}
}
int main()
{
	int u,v;
	scanf("%d",&t);
	while(t--)
	{
		cin>>n>>a>>b>>da>>db;
		init();
		for(int i=1;i<n;i++)
		{
			cin>>u>>v;
			add(u,v);add(v,u);
		}
		ans=0;//记录a,b间距离 
		dfs(a,0);
		if(ans<=da)
		{
			cout<<"Alice"<<endl;
			continue;
		}
		for(int i=1;i<=n;i++)
		vis[i]=0;
		mmax=0;
		dfs1(1,0);//找到直径的一个端点 
		for(int i=1;i<=n;i++)
		vis[i]=0;
		mmax=0;
		dfs1(x,1);//算出直径的长度 
		if(da<mmax/2&&db>da*2)
		cout<<"Bob"<<endl;
		else
		cout<<"Alice"<<endl;
	}	
}

E.Fixed Point Removal

题意:给一个数列a,若a[i]==i则可以删除,删除后左右部分连接。询问q(x,y),前x个,后y个元素变为n+1,问每次询问能删几个数。
思路:首先,进行转换a[i]=i-a[i];则a[i]的含义变为i位置左边若能删除a[i]个元素,则a[i]可以删除。
若f(l,r)表示[l,r]区间最多能删除的数的个数,则\(f[l][r]=f[l][r-1]+1(0<=a[r]<=f[l][r-1])\),若a[i]不满足则\(f[l][r]=f[l][r-1]\)。因为f(l,r)对于相同的r具有单调性,所以我们每次可以在树状数组上二分找点。(代码网上找的...)

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 300010

int n,m,a[maxn];
struct TREE{
	int tr[maxn];
	void add(int x){for(;x<=n;x+=(x&-x))tr[x]++;}
	int sum(int x){int re=0;for(;x;x-=(x&-x))re+=tr[x];return re;}
}tr;
struct par{int x,pos;};
vector<par>q[maxn];
int ans[maxn];

int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i]=i-a[i];
	for(int i=1,x,y;i<=m;i++)scanf("%d %d",&x,&y),q[n-y].push_back((par){1+x,i});
	for(int i=1;i<=n;i++){
		if(a[i]>=0){
			int l=1,r=i,p=-1;
			while(l<=r){
				int mid=l+r>>1;
				if(tr.sum(i)-tr.sum(mid-1)>=a[i])p=mid,l=mid+1;
				else r=mid-1;
			}
			if(p!=-1)tr.add(p);
		}
		for(par j:q[i]){
			ans[j.pos]=tr.sum(i)-tr.sum(j.x-1);
		}
	}
	for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
}
posted @ 2020-09-07 20:21  清街老酒  阅读(194)  评论(0编辑  收藏  举报