codeforces contest 353

http://codeforces.com/contest/353

//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

A 353A Domino

题意:给出n个数对(a,b),使suma,sumb都为偶数最少需要交换几个数对。不能做到输出-1。

题解:求出suma,sumb判断是否需要交换。判断是否存在((a+b)&1)==1,存在才可以交换。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << endl
int main() {
	int n;
	while(~scanf("%d",&n)) {
		int x,y,sumx=0,sumy=0,flag=0;
		for(int i=1;i<=n;++i) {
			scanf("%d%d",&x,&y);
			sumx+=x;
			sumy+=y;
			if((x+y)&1) flag=1;
		}
		if((sumx&1)&&(sumy&1)&&flag) {
			puts("1");
		} else if((sumx%2==0)&&(sumy%2==0)) {
			puts("0");
		} else {
			puts("-1");
		}
	} 
    return 0;
}


//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

B 353B Two Heaps

题意:给出2n个数(10 ≤ ai ≤ 99),把他们均分成两部分A和B,A,B中重复出现的元素当成一个元素。求分配的方案,使|A|*|B|最大。

题解:把所有数分成:出现过两次以上和出现过两次以下的(包括两次)。(剩下的懒得写了,看代码吧)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << endl
const int N=105;
struct Node {
    int a,i;
}a[2*N],b[2*N],c[2*N];
bool cmp(Node a,Node b) {
    if(a.a==b.a) return a.i<b.i;
    return a.a<b.a;
}
int ans[2*N],ti[N];
map<int,int> mp1,mp2;
int main() {
	int n;
	while(~scanf("%d",&n)) {
        int m=0,k=0;
        memset(ti,0,sizeof(ti));
        for(int i=1;i<=2*n;++i) {
            scanf("%d",&a[i].a);
            a[i].i=i;
            ++ti[a[i].a];
            if(ti[a[i].a]<=2) b[++m]=a[i];
            else c[++k]=a[i];
        }
        sort(b+1,b+1+m,cmp);
        mp1.clear();
        mp2.clear();
        for(int i=1;i<=m;++i) {
            int j=b[i].i;
            if(i&1) {
                ans[j]=1;
                ++mp1[b[i].a];
            } else {
                ans[j]=2;
                ++mp2[b[i].a];
            }
        }
        for(int i=1;i<=k;++i) {
            int j=c[i].i;
            if((i+m)&1) {
                ans[j]=1;
                ++mp1[c[i].a];
            } else {
                ans[j]=2;
                ++mp2[c[i].a];
            }
        }
        printf("%d\n",mp1.size()*mp2.size());
        for(int i=1;i<=2*n;++i) printf("%d%c",ans[i],(i==2*n)?'\n':' ');
	}
    return 0;
}


//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

C 353C Find Maximum

题意:给出n个数和一个二进制数m。,x属于1~m。求最大的f(x)

题解:一开始想的是,如果不取最高位,那么低位全为1肯定是最优的。现在如何判断取最高位的情况呢?

我们可以用i遍历最高位到最低位,i之前的位都不变,i之后的位都变成1(bit(i)==1)。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << endl
const int N=100005;
int a[N],sum[N];
char s[N];
int main() {
    int n;
    while(~scanf("%d",&n)) {
        for(int i=1;i<=n;++i) scanf("%d",a+i);
        scanf("%s",s+1);

        int p=-1;//最高位的1
        for(int i=n;i>=1;--i) {
            if(s[i]-'0') {
                p=i;
                break;
            }
        }

        if(p==-1) {
            puts("0");
            continue;//没有1
        }

        //不变的情况
        int ans=0;
        for(int i=1;i<=n;++i) {
            if(s[i]-'0') ans+=a[i];
            sum[i]=sum[i-1]+a[i];
        }

        int res=0;
        for(int i=p;i>=1;--i) {
            //i之前的都不变,之后的都为1(当前位是1才可以)
            if(s[i]-'0') {
                ans=max(ans,res+sum[i-1]);
                res+=a[i];
            }
        }

        printf("%d\n",ans);

    }
    return 0;
}





//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

D  353D  Queue
题意:每次交换相邻的F和M(可以同时交换多个),使得最后F都在M前面。求最小交换次数。
题解:计算每个F要往前移动几个,和它会被堵住几次。
注意:M只能起到缓解作用,不是消除作用。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << endl
const int N=1000005;
char s[N]; 
int a[N],b[N];
int main() {
	while(~scanf("%s",s+1)) {
		int n=strlen(s+1);
		int m=0,cnt=0;
		for(int i=1;i<=n;++i) {
			if(s[i]=='F') {
				a[i]=i-(++m);//要往前移动多少 
				if(a[i]) b[i]=cnt++;//会被堵住多久(跳过开头的FFF)
			} else {
				if(cnt) --cnt;
			}
		}
		int ans=0;
		for(int i=1;i<=n;++i) {
			if(s[i]=='M') continue;
			if(a[i]) ans=max(ans,a[i]+b[i]);
			//printf("%d %d %d\n",i,a[i],b[i]);
		}
		printf("%d\n",ans);
	}
    return 0;
}



//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

E  353E  Antichain
题意:有一个图,结点编号0~n-1。用一个长度n,只由01组成的字符串s[0~n-1]表示图的所有边。 s[i]==0表示有向边<i,i+1>, s[i]==1表示有向边<i+1,i>。如果u能到达v或者v能到达u,那么称u与v可达。找出一个最大的集合,集合中的点互不可达。输出集合大小。
题解:画一下图,把所有互相可达的集合圈起来。可以看出一种贪心的解法。首先大小大等于2的集合肯定能取一个,现在我们只要考虑大小为2的集合。画一下图找规律可以看出,连续cnt个大小为2的集合能取cnt/2个。我们还要考虑开头结尾都有连续的1的情况。(有很多AC代码没考虑这个,但是也能AC。反例100110,答案3。)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << endl
const int N=1000005;
char s[N]; 
int a[N];
int main() {
	while(~scanf("%s",s+1)) {
		int n=strlen(s+1);
		int m=0,cnt=0;
		s[0]=s[1];
		s[n+1]=1-(s[n]-'0')+'0';
		for(int i=1;i<=n+1;++i) {
			if(s[i]==s[i-1]) {
				++cnt;
			} else {
				a[++m]=cnt;
				cnt=1;
			}
		}
		
		if(m&1) {
			a[1]+=a[m];
			--m;
		}
		
		int flag=0;
		for(int i=1;i<=m;++i) {
			if(a[i]>=2) flag=1;
		}
		
		//去掉这个也能AC,但是有反例
		//100110 
		int p=1; 
		if(flag) {
			while(a[p]==1) {
				a[++m]=a[p++];
			}
		}
		int ans=0; cnt=0;
		for(int i=p;i<=m;++i) {
			if(a[i]>=2) {
				ans+=cnt/2+1;
				cnt=0;
			} else {
				++cnt;
			}
		}
		ans+=cnt/2;
		printf("%d\n",ans);
	}
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值