Codeforces Round #565 (Div. 3)

A.模拟即可,最多不会超过3logn次

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
int n,ans;
long long x;
int main()
{
	scanf("%d",&n);
	while (n--)
	{
		scanf("%lld",&x); ans=0;
		while (x>1)
		{
			bool ff=0;
			if (x%2==0) x/=2,ff=1;
			else if (x%3==0) x/=3,x*=2,ff=1;
			else if (x%5==0) x/=5,x*=4,ff=1;
			ans++;
			if (!ff) break;
		}
		if (x==1) printf("%d\n",ans);else printf("-1\n");
	}
return 0;
}

B.贪心,先把3的倍数全弄出来,然后考虑%3为1,2的配对,然后考虑各自配对

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;
const int maxn=110;
int T,n,x,ans,num1,num2;
int main()
{
	scanf("%d",&T);
	while (T--)
	{
		scanf("%d",&n); ans=0; num1=0; num2=0;
		for (int i=1;i<=n;i++) 
		{
			scanf("%d",&x); x%=3;
			if (x==0) ans++;
			if (x==1) num1++;
			if (x==2) num2++;
		}
		int k=min(num1,num2);
		ans+=k; num1-=k; num2-=k;
		printf("%d\n",ans+num1/3+num2/3);
	}
return 0;
}

C.贪心,对于同一个字母,若在前面能构成合法序列的话一定比在后面优

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
const int maxn=500010;
int n,a[maxn],ans,sum[50];
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	for (int i=1;i<=n;i++)
	if (a[i]==4) sum[4]++;
	else if (a[i]==8 && sum[4]) sum[4]--,sum[8]++;
	else if (a[i]==15 && sum[8]) sum[8]--,sum[15]++;
	else if (a[i]==16 && sum[15]) sum[15]--,sum[16]++;
	else if (a[i]==23 && sum[16]) sum[16]--,sum[23]++;
	else if (a[i]==42 && sum[23]) sum[23]--,ans++;
	printf("%d\n",n-6*ans);
return 0;
}

D.排序,首先对于合数,从大往小找是否有最大因子,有的话就是原数列,对于剩下的质数从小往大找

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int maxn=400010;
int n,a[maxn],prime[2*maxn],cnt,num[3000010],ans[maxn],topt;
bool f[3000010];
bool cmp(int aa,int bb){return aa>bb;}
int main()
{
	memset(f,1,sizeof f); f[0]=f[1]=0;
	for (int i=2;i<=3000000;i++)
	{
		if (f[i]) prime[++cnt]=i;
		for (int j=1;j<=cnt && 1ll*i*prime[j]<=3000000;j++)
		{
			f[i*prime[j]]=0;
			if (i%prime[j]==0) break;
		}
	}
	scanf("%d",&n); n*=2; for (int i=1;i<=n;i++) scanf("%d",&a[i]),num[a[i]]++;
	sort(a+1,a+n+1,cmp);
	for (int i=1;i<=n;i++)
	if (!f[a[i]] && num[a[i]])
	{
		int x; for (x=2;1ll*x*x<=a[i];x++) if (a[i]%x==0) break;
		if (num[a[i]/x]) ans[++topt]=a[i],num[a[i]]--,num[a[i]/x]--;
	}
	for (int i=n;i>=1;i--)
	if (f[a[i]] && num[a[i]])
	{
		if (num[prime[a[i]]]) ans[++topt]=a[i],num[a[i]]--,num[prime[a[i]]]--;
	}
	for (int i=1;i<=topt;i++) printf("%d ",ans[i]);
return 0;
}

E.问题等价于对于图中的每条边,我们要使其两端的端点至少有一个被选中,这就变成了黑白染色问题,最后黑白两点谁少就输出谁

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
using namespace std;
const int maxn=200010;
int T,n,m,topt,st[maxn<<1],nt[maxn<<1],to[maxn<<1],col[maxn],sum1,sum2;
bool f[maxn];
void add(int x,int y)
{to[++topt]=y; nt[topt]=st[x]; st[x]=topt;}
void init()
{
	for (int i=1;i<=topt;i++) st[i]=0;
	topt=0; sum1=sum2=0;
}
void dfs(int x,int co)
{
	f[x]=1; col[x]=co; int p=st[x];
	if (co) sum1++;else sum2++;
	while (p)
	{
		if (!f[to[p]]) dfs(to[p],co^1);
		p=nt[p];
	}
}
int main()
{
	scanf("%d",&T);
	while (T--)
	{
		init(); scanf("%d%d",&n,&m);
		for (int i=1;i<=n;i++) f[i]=0,col[i]=0;
		for (int i=1;i<=m;i++)
		{
			int xx,yy; scanf("%d%d",&xx,&yy);
			add(xx,yy); add(yy,xx);
		}
		dfs(1,0);
		if (sum1<sum2) 
		{
			printf("%d\n",sum1);
			for (int i=1;i<=n;i++) if (col[i]) printf("%d ",i);
			printf("\n");
		}
		else 
		{
			printf("%d\n",sum2);
			for (int i=1;i<=n;i++) if (!col[i]) printf("%d ",i);
			printf("\n");
		}
	}
return 0;
}

F.dp,对于每轮将攻击力从大到小排序,处理两个数组,a[i][j],b[i][j]表示这一轮花费了i的费用,这一轮选了j个最大攻击力(a表示第一个选的攻击力翻倍,b正常),对于每轮,0/1背包搞一搞,对于全局,维护一个dp[i][j]表示当前打了i轮,已经打了j个人(模10)的最大值,用a.b转移一波就ok了

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const int maxn=200010;
int T,n,t;
long long dp[2][12],k,ans,a[5][5],b[5][5];
struct da{int c;long long v;}q[maxn];
bool cmp(da aa,da bb)
{
	if (aa.v==bb.v) return aa.c<bb.c;
	return aa.v>bb.v;
}
int main()
{
	scanf("%d",&T); memset(dp[t],-1,sizeof dp[t]); dp[t][0]=0;
	while (T--)
	{
		scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d%lld",&q[i].c,&q[i].v);
		memset(a,-1,sizeof a); memset(b,-1,sizeof b);  a[0][0]=0; b[0][0]=0;
		t^=1; memset(dp[t],-1,sizeof dp[t]); sort(q+1,q+n+1,cmp);
		for (int i=1;i<=n;i++)
		 for (int j=3-q[i].c;j>=0;j--)
		  for (int k=0;k<3;k++)
		  {
		 	if (a[k][j]!=-1)
		 	{
		 		if (j==0) a[k+1][j+q[i].c]=max(a[k+1][j+q[i].c],a[k][j]+2ll*q[i].v);
		 		else a[k+1][j+q[i].c]=max(a[k+1][j+q[i].c],a[k][j]+q[i].v);
		 	}
		 	if (b[k][j]!=-1) b[k+1][j+q[i].c]=max(b[k+1][j+q[i].c],b[k][j]+q[i].v);
		  }
		for (int i=0;i<=9;i++)
		 for (int j=0;j<=3;j++)
		  for (int k=0;k<=3;k++)
		  if (dp[t^1][i]!=-1)
		  {
		  	  if (i+j>=10 && a[j][k]!=-1) dp[t][(i+j)%10]=max(dp[t][(i+j)%10],dp[t^1][i]+a[j][k]);
		   	   else if (b[j][k]!=-1) dp[t][(i+j)%10]=max(dp[t][(i+j)%10],dp[t^1][i]+b[j][k]);
		  }
	}
	for (int i=0;i<10;i++) ans=max(ans,dp[t][i]);
	printf("%lld\n",ans);
return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值