• Codeforces Global Round 3


    Codeforces Global Round 3

    A. Another One Bites The Dust

    有若干个a,有若干个b,有若干个ab。你现在要把这些串拼成一个串,使得任意两个相邻的位置都是不同字符,求可能的最长串长度。

    枚举一下(a)开头还是(b)开头,那么接下来就被唯一确定了。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int a,b,c;long long ans;
    int main()
    {
    	scanf("%d%d%d",&a,&b,&c);
    	ans=0ll+c*2+min(a,b+1)+min(a,b);
    	if(b)--b,ans=max(ans,1ll+c*2+min(a,b+1)+min(a,b));
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    B. Born This Way

    (n)个航班从(A)前往(B),起飞时间分别是(a_1,a_2,...,a_n),飞行时间都是(t_a)。有(m)个航班从(B)前往(C),起飞时间分别是(b_1,b_2,...,b_m),飞行时间是(t_b)。现在有一个人要从(A)(C),你可以取消不超过(k)个航班,使得这个人到达(C)的时间最晚。
    求出最晚时间,如果可以让这个人无法到达,输出(-1)

    显然这个人越早到达(B)越好,所以我们取消掉的一定是(a)的一段前缀。而到达(B)之后一定会坐上最早出发的航班,所以同理删去到达之后的一段连续的航班。
    那么枚举一下在(a)删掉的前缀长度就行了。
    注意判断一下(nle k,mle k)的情况

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define MAX 200200
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,m,ta,tb,k,ans;
    int a[MAX],b[MAX];
    int main()
    {
    	n=read();m=read();ta=read();tb=read();k=read();
    	for(int i=1;i<=n;++i)a[i]=read();
    	for(int i=1;i<=m;++i)b[i]=read();
    	if(n<=k||m<=k){puts("-1");return 0;}
    	for(int i=0,p=1;i<=n&&i<=k;++i)
    	{
    		while(p<=m&&b[p]<a[i+1]+ta)++p;
    		if(m-p+1+i<=k){puts("-1");return 0;}
    		ans=max(ans,b[p+k-i]+tb);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    C. Crazy Diamond

    你有一个长度为(n)的一个排列(p),其中(n)是一个偶数。
    你的任务是要把这个排列排序,两个位置可以交换当前仅当满足(2|i-j|ge n)
    你需要构造一个交换次数不超过(5n)的交换方式。

    考虑顺次把每个数归位的过程。
    分情况讨论一下,假设当前第(i)个数在位置(p)
    如果(p,i)两个位置可以直接交换,那么就直接交换。
    否则如果(p,i)都可以和(1)交换,那么通过(1)进行交换就行。
    否则如果(p,i)都可以和(n)交换,那么通过(n)进行交换就行。
    否则(p)可以和(1)(i)可以和(n)交换,那么通过((p,1),(i,n),(1,n),(p,1),(i,n))这样(5)次操作就可以交换。
    所以最坏情况下就是(5n)次。

    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    #define MAX 300300
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,p[MAX],b[MAX];
    bool chk(int i,int j){return 2*abs(i-j)>=n;}
    vector<pair<int,int> > Ans;
    void add(int i,int j){if(i==j)return;swap(p[i],p[j]);b[p[i]]=i;b[p[j]]=j;Ans.push_back(make_pair(i,j));}
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;++i)b[p[i]=read()]=i;
    	for(int i=1;i<=n;++i)
    	{
    		if(i==b[i])continue;
    		if(chk(b[i],i))add(i,b[i]);
    		else
    		{
    			int p=b[i];
    			if(chk(1,p)&&chk(1,i))add(1,p),add(1,i),add(1,p);
    			else if(chk(n,i)&&chk(p,n))add(n,i),add(p,n),add(n,i);
    			else if(chk(1,p)&&chk(i,n))add(1,p),add(i,n),add(1,n),add(1,p),add(i,n);
    		}
    	}
    	printf("%d
    ",(int)Ans.size());
    	for(auto p:Ans)printf("%d %d
    ",p.first,p.second);
    	return 0;
    }
    

    D. Dirty Deeds Done Dirt Cheap

    给定两个长度为(n)的数列(a,b),保证所有数都在([1,2n])中且各不相同。
    现在你要选出尽可能多的在([1,n])的数,使他们构成一个数列({i}),满足数列:
    (a_{i1}b_{i1}a_{i2}b_{i2}...a_{im}b_{im})是一个波动序列。
    即每个数都同时大于相邻的两个数或者小于相邻的两个数。

    首先数列有两种形式,第一种是(<><><>)这样子,第二种是(><><><)在这样子。
    那么这样子就确定了((a_i,b_i))组内的大小关系,可以把二元组分成两类,两类只能分别构造答案。
    那么一个二元组可以连在另外一个二元组前面,当前仅当(b_i<a_j)或者(b_i>a_j)
    假如我们只考虑(b_i<a_j)的情况。考虑把所有数按照(a_i)排序,这样子每个二元组的出边就是一个后缀,那么我们只需要贪心的把边连到(b)最小的上面去就行了,这样子拿线段树就可以维护了,或者进一步,发现(b)是单增的,所以用堆之类的东西维护就行了。
    然而这样子很呆。
    我们换一种考虑的方法,因为(b)是单增的,所以我们直接按照(b)排序,此时发现按照排序之后的结果就是合法的。
    因为(a_{i}>b_{i}<b_{i+1},a_{i+1}>b_{i+1})
    所以有(a_{i}>b_{i}<a_{i+1}>b_{i+1})
    类似的,反过来(b_i>a_j)按照(a)排序就行了。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define MAX 300300
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,r,a[MAX],b[MAX],p[MAX];
    bool cmpb(int x,int y){return b[x]<b[y];}
    bool cmpa(int x,int y){return a[x]<a[y];}
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;++i)a[i]=read(),b[i]=read(),r+=a[i]>b[i],p[i]=i;
    	printf("%d
    ",max(r,n-r));
    	if(r>n-r)
    	{
    		sort(&p[1],&p[n+1],cmpb);
    		for(int i=1;i<=n;++i)
    			if(a[p[i]]>b[p[i]])printf("%d ",p[i]);
    	}
    	else
    	{
    		sort(&p[1],&p[n+1],cmpa);
    		for(int i=n;i;--i)
    			if(a[p[i]]<b[p[i]])printf("%d ",p[i]);
    	}
    	puts("");
    	return 0;
    }
    

    E. Earth Wind and Fire

    数轴上有(n)个石头,一开始时第(i)个石头在位置(s_i),每次你可以选择两个石头(i,j),满足(s_i<s_j),然后选择一个(d),满足(2dle |s_i-s_j|),然后把(i)移动到(s_i+d)位置,(j)移动到(s_j-d)位置。
    给定一个长度为(n)的数列(t),表示最终在(t_i)位置要有一个石头。
    问能否满足条件。
    如果可以构建一个方案。

    不难发现如果合法我们一定可以不改变相对顺序。
    那么起始位置和目标位置做差之后,如果是要向右移动,那么我们直接压进栈里面。
    否则从栈顶取元素进行移动。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    #define MAX 300300
    #define mp make_pair
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,t[MAX],f;
    pair<int,int> s[MAX],Q[MAX];
    vector<pair<pair<int,int>,int> >Ans;
    void add(int i,int j,int d)
    {
    	i=s[i].second,j=s[j].second;
    	Ans.push_back(mp(mp(i,j),d));
    }
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;++i)s[i]=make_pair(read(),i);
    	for(int i=1;i<=n;++i)t[i]=read();
    	sort(&t[1],&t[n+1]);sort(&s[1],&s[n+1]);
    	for(int i=1;i<=n;++i)
    		if(s[i].first<t[i])
    			Q[++f]=mp(i,t[i]-s[i].first);
    		else
    		{
    			if(s[i].first==t[i])continue;
    			int p=s[i].first-t[i];
    			while(p&&f)
    			{
    				int mv=min(p,Q[f].second);
    				add(Q[f].first,i,mv);
    				p-=mv;Q[f].second-=mv;
    				if(!Q[f].second)--f;
    			}
    			if(p){puts("NO");return 0;}
    		}
    	if(f){puts("NO");return 0;}
    	puts("YES");
    	printf("%d
    ",(int)Ans.size());
    	for(auto p:Ans)printf("%d %d %d
    ",p.first.first,p.first.second,p.second);
    	return 0;
    }
    

    F. Foo Fighters

    你有(n)个物品,每个物品有两个权值(val)(mask)
    你可以选择一个数(s),然后修改所有数的(val),如果(val& mask)有奇数个(1)就把(val)变成(-val)
    输出一个(s),使得权值和符号变反。

    显然可以把所有位分开考虑,如果选择了这一位并且这一位的(mask)上有(1)就可以直接取反。
    现在的问题变成了我们要选择哪些位置。
    首先位与位之间是么有顺序关系的,所以我们随意用什么顺序考虑都是可行的,不妨从高位往低位处理。
    我们用类似归纳法的思想来考虑,我们先不妨令数字和是正数(如果是负数可以把所有东西全部取反)
    如果我们已经处理完了若干位,如果已经让数字和变成了负数,那么结束了。
    否则的话,考虑是否改变这一位上的所有值,但是如果只考虑位的话如果这一位选了会影响后面的选择,所以不能直接这样贪心。
    我们钦定每个数的正负只在其最低位的时候考虑,因为这些数如果在这一位不改就不能再改了,所以每个数就只会被考虑一次。那么如果以这一位为最低位的数的权值和为正数,那么直接取反就行了。
    至于为啥是对的。。。emmm,窝感觉很对QwQ。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define ll long long
    #define MAX 300300
    inline ll read()
    {
    	ll x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,v[MAX];
    ll a[MAX],s,sum;
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;++i)v[i]=read(),a[i]=read(),sum+=v[i];
    	if(sum<0)for(int i=1;i<=n;++i)v[i]=-v[i];
    	for(int i=62;~i;--i)
    	{
    		ll ss=0;
    		for(int j=1;j<=n;++j)if(a[j]==(1ll<<i))ss+=v[j];
    		if(ss>0)s|=1ll<<i;
    		for(int j=1;j<=n;++j)
    			if(a[j]&(1ll<<i))
    			{
    				a[j]^=1ll<<i;
    				if(ss>0)v[j]=-v[j];
    			}
    	}
    	printf("%lld
    ",s);
    	return 0;
    }
    

    G. Gold Experience

    (n)个点,每个点有一个点权(a_i),如果两个点权的(gcd>1),那么他们之间就会连上一条边。
    定义一个集合中的一个点是好的,当前仅当这个点和点集中其他所有点都有连边。
    你要找到一个大小为(k)的点集,满足其中所有点都是好的或者所有点都是不好的。

    咕咕咕咕

    H. Holy Diver

    咕咕咕

  • 相关阅读:
    android ndk 调试问题
    音频
    文件分割与c语言文件结
    本机抓包
    rtm匹 转
    mac 工具等效率
    【MySQL】Explain Tutorial
    Sed基本入门[5] Sed Hold and Pattern Space Commands
    Sed基本入门[3] Regular Expressions
    Protocol Buffer Basics
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10984063.html
Copyright © 2020-2023  润新知