Codeforces Round #697 (Div. 3)

A

 

求一个数是否有奇因子

一直除以二即可

 

代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	int t;
	scanf("%d",&t);
	while(t--)
	{
		long long n;
		scanf("%lld",&n);
		while(n%2==0) n/=2;
		if(n==1) printf("NO\n");
		else printf("YES\n");
	}
	return 0;
}

B

求一个数是否能被表达成x2020+y2021=n的形式

如果n%2020的余数<=n/2020,就可以表示

 

代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	int t;
	scanf("%d",&t);
	while(t--)
	{
		long long n;
		scanf("%lld",&n);
		int cnt=n/2020;
		int yu=n-2020*cnt;
		if(yu<=cnt) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

 

C

 

一道不错的容斥题,考虑每个男生和另一个男生的可以选择的组数的和,所以sum=(\sum cnta[i])^2-cnta[i]^2,然后再减去选重女生的可能sum-=_{2}^{cntb[i]}\textrm{C}

 

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,m,k,a[maxn],b[maxn]; 
ll ans,sum,minn;
int cnta[maxn],cntb[maxn];
int main()
{
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	int t;
	scanf("%d",&t);
	while(t--)
	{
		ans=sum=minn=0;
		scanf("%d%d%d",&n,&m,&k);
		for(int i=1;i<=n;i++) cnta[i]=0;
		for(int i=1;i<=m;i++) cntb[i]=0;
		for(int i=1;i<=k;i++) scanf("%d",&a[i]);
		for(int i=1;i<=k;i++) scanf("%d",&b[i]);
		for(int i=1;i<=k;i++)
		{
			cnta[a[i]]++;
			cntb[b[i]]++;
		}
		for(int i=1;i<=n;i++)
			sum+=cnta[i],minn+=1LL*cnta[i]*cnta[i];
		minn/=2;
		for(int i=1;i<=m;i++)
			minn+=1LL*cntb[i]*(cntb[i]-1)/2;
		ans=1LL*sum*sum/2-minn;
		printf("%lld\n",ans);
	}
	return 0;
}

 

D

 

维护两个序列,从大到小放代价为1和代价为2的两组数

贪心的比较:两个1和一个2的内存之比,哪个大就选择哪个

注意还有几个需要注意的细节:1.最后有可能只需要一个代价为1的即可  2.最后一步选了一个代价为2的,可能超过所需删除的内存,可以撤销一次代价为1的操作,这里最多只有一次,可以考虑一下为什么

 

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,m,a[maxn],b[maxn]; 
int cnta[maxn],cntb[maxn],pa,pb;
bool cmp(int x,int y)
{
	return x>y;
}
int main()
{
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	int t;
	scanf("%d",&t);
	while(t--)
	{
		pa=pb=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		for(int i=1;i<=n;i++) scanf("%d",&b[i]);
		for(int i=1;i<=n;i++)
		{
			if(b[i]==1)
				cnta[++pa]=a[i];
			else cntb[++pb]=a[i];
		}
		sort(cnta+1,cnta+pa+1,cmp);
		sort(cntb+1,cntb+pb+1,cmp);
		ll mem=0;
		cnta[pa+1]=cntb[pb+1]=0;
		int ans=0,posa=0,posb=0;
		while(mem<m && (posa<pa || posb<pb))
		{
			if(posb==pb || mem+cnta[posa+1]>=m)
			{
				ans++; posa++;
				mem+=cnta[posa];
				if(mem>=m) break;
				else continue; 
			}
			if(pa-posa>=2)
			{
				if(cnta[posa+1]+cnta[posa+2]>cntb[posb+1])
				{
					posa++; mem+=cnta[posa];
					posa++; mem+=cnta[posa]; 
					ans+=2;
				}
				else
				{
					posb++; mem+=cntb[posb];
					ans+=2;
					if(posa && mem-m>=cnta[posa])
					{
						ans--;
						mem-=cnta[posa];
						posa--;
					}
				}
			}
			else
			{
				ans+=2;
				posb++; mem+=cntb[posb];
				if(posa && mem-m>=cnta[posa])
				{
					ans--;
					mem-=cnta[posa];
					posa--;
				}
			}
		}
		if(mem<m) printf("-1\n");
		else printf("%d\n",ans);
	}
	return 0;
}

 

E

 

给定一个序列,从中寻找和为最大的可能方案

排序后,枚举值为a[k]的个数cnt,在k以内的有cnta个,答案显而易见就是C_{cnt}^{cnta}

 

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1005;
const ll MOD=1e9+7; 
int n,m,a[maxn];
bool cmp(int x,int y)
{
	return x>y;
}
ll c[maxn][maxn];
void C()
{
    int i,j;
    for(i=0;i<maxn;i++)
        c[i][0]=c[i][i]=1;
    for(i=1;i<maxn;i++)
        for(j=1;j<=i;j++)
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
}
int main()
{
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	int t;
	scanf("%d",&t);
	C();
	while(t--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		sort(a+1,a+n+1,cmp);
		int dig=a[m],cnt=0,cnta=0;
		for(int i=m;i>=1;i--)
		{
			if(a[i]!=dig) break;
			cnt++; cnta++;
		}
		for(int i=m+1;i<=n;i++)
		{
			if(a[i]!=dig) break;
			cnt++;
		}
		ll ans=c[cnt][cnta];
		printf("%lld\n",ans);
	}
	return 0;
}

 

F

 

待续

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值