codeforces contest 332

http://codeforces.com/contest/332

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

B 332B Maximum Absurdity

题意:给出数组a[1~n],从中选取两段连续的,长度为k的数组,使他们的和最大。

题解:首先我们可以把长度为k的连续段的和存起来。枚举第二段(对于第二段的每次的方案,第一段都在它的前面)。

我们如何得知每次方案,第一段的最优解呢?对于第i次方案,它比i-1次方案往后移了一个元素,在方案i-1中,它的第一段肯定处于最优解了,所以d[i](第i段的最优解)=max(sum[i],d[i-1])

然后每次方案维护一下ans就行。

#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=200005;
ll a[N],sum[N];
int main() {
	int n,k;
	while(~scanf("%d%d",&n,&k)) {
		for(int i=1;i<=n;++i) scanf("%I64d",&a[i]);
		sum[1]=0;
		for(int i=1;i<=k;++i) sum[1]+=a[i];
		for(int i=2;i+k-1<=n;++i) sum[i]=sum[i-1]+a[i+k-1]-a[i-1];
		int l=1,r=k+1,ansl=1,ansr=k+1;
		for(int i=l;r+k-1<=n;++r,++i) {
            if(sum[i]>sum[l]) l=i;
            if(sum[l]+sum[r]>sum[ansl]+sum[ansr]) ansl=l,ansr=r;
		}
		printf("%d %d\n",ansl,ansr);
	}
    return 0;
}


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

C 332C Students' Revenge

题意:有n个议案,每个议案有a,b两个值。学生们可以决定让主席从其中的p个议案挑选k个。

主席挑选k个议案的原则是:首先保证b的和尽量大,然后保证a的和尽量小。

学生挑选p个议案的原则是:保证主席选中的k的议案的a的和尽量大,再保证p个议案的b的和尽量大。

题解:我们需要考虑一个问题:如何让老师挑选我们准备的p个方案其中的k个?

p-k个议案的b一定比k个议案的b小。很明显的,所有议案中最小的p-k个b肯定不能选,所以我们标记它。然后选择剩下议案中k个a最大的,并且把其中最小的b记作minb。最后选择b比minb小的最大的几个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=100005;
struct Node {
    int a,b,i;
}a[N];
bool cmp1(Node a,Node b) {
    if(a.b==b.b) return a.a>b.a;
    return a.b<b.b;
}
bool cmp2(Node a,Node b) {
    if(a.a==b.a) return a.b<b.b;
    return a.a<b.a;
}
int main() {
    int n,p,k;
    while(~scanf("%d%d%d",&n,&p,&k)) {
        for(int i=1;i<=n;++i) {
            scanf("%d%d",&a[i].a,&a[i].b);
            a[i].i=i;
        }
        int cnt1=p-k,cnt2=k;

        sort(a+1,a+1+n,cmp1);

        sort(a+1+p-k,a+1+n,cmp2);
        int minb=a[n].b;
        for(int i=n;cnt2--;--i) {
        	printf("%d ",a[i].i);
        	minb=min(minb,a[i].b);
		}

		sort(a+1,a+1+n-k,cmp1);
		int r=n-k;
		while(a[r].b>=minb) --r;
		r=max(r,p-k);
        for(int i=r;i>=1&&cnt1--;--i) printf("%d ",a[i].i);

        puts("");
    }
    return 0;
}


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

D 332D Theft of Blueprints

题意:给出一个n顶点图和它的邻接矩阵。对于每个大小为k的集合,刚好有一个点能到达这k个点。记他们边权的和为sum。求sum的平均值。(向下取整)

题解:关键条件是[刚好有一个点能到达这k个点],所以我们枚举每一个点,它的所有边边权都会被加上C(deg-1,k-1)次。

数很大,好像会爆long double(避开了,没去检验。)还要注意一下long double不能直接输出。

#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=2005;
int mp[N][N];
int main() {
    int n,k;
    while(~scanf("%d%d",&n,&k)) {
        for(int i=1;i<n;++i) {
            for(int j=i+1;j<=n;++j) {
                scanf("%d",&mp[i][j]);
                mp[j][i]=mp[i][j];
            }
        }
        long double ans=0;
        for(int i=1;i<=n;++i) {
            int cnt=0;
            long double sum=0;
            for(int j=1;j<=n;++j) {
                if(j!=i&&mp[i][j]!=-1) {
                    sum=sum+mp[i][j];
                    ++cnt;
                }
            }
            int kk=min(k-1,cnt-1-(k-1));
            for(int t=1;t<=kk;++t) sum=sum*(t+cnt-1-kk);
    		for(int t=1;t<=kk;++t) sum=sum/t;
    		if(kk<0) sum=0;
            ans=ans+sum;
        }
    	k=min(k,n-k);
	    for(int i=1;i<=k;++i) ans=ans*i;
	    for(int i=1;i<=k;++i) ans=ans/(i+n-k);
        printf("%I64d\n",(ll)ans);
    }

    return 0;
}


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

E  332E  Binary Key
题意:如果知道字符串s1和key,就能求出s2。key串由01组成,扫一遍s1[0~len1-1]串,如果key[i%k]==1,s2+=s1[i]。现在给你s1,s2和key的长度,求字典序最小的key。
题解:我觉得很难啊!题解很巧妙啊!
#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 K=2005;
string s1,s2,str1[K],str2[K];
int main() {
	getline(cin,s1);getline(cin,s2);
	int k; scanf("%d",&k);
	int len1=s1.length();
	int len2=s2.length();
	
	//预处理第一个串 
	for(int i=0;i<len1;++i) str1[i%k]+=s1[i]; 
	
	string ans="222";
	int t=min(len2,k);
	for(int i=1;i<=t;++i) {//枚举第二个字符串的“周期” 
		for(int j=0;j<i;++j) str2[j]="";
		for(int j=0;j<len2;++j) str2[j%i]+=s2[j]; 
		string tmp="";
		//判断这次是否符合
		int p=i-1;
		for(int j=k-1;j>=0;--j) {
			if(p>=0&&str1[j]==str2[p]) {
				--p;
				tmp+="1";
			} else {
				tmp+="0";
			}
		} 
		if(p<0) {
			reverse(tmp.begin(),tmp.end());
			ans=min(ans,tmp);
		}
	}
	
	if(ans=="222") ans="0";
	cout<<ans<<endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值