CodeCraft-21 and Codeforces Round #711 (Div. 2)A-D题解

题目链接:
https://codeforces.com/contest/1498

A. GCD Sum

题意

给定一个数n,求这个数和他每个位上的数的和的GCD。如果这个GCD是1,那么找比n大的,且最近的满足这个GCD>1的数。

思路:
按照题意模拟后发现,最坏的情况也是n+2的时候就找到了,所以,n最多加2。然后按照题意模拟即可

AC代码

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
typedef long long ll;
ll t,n;
string s;
ll p;
int main()
{
	IOS
	cin>>t;
	while(t--)
	{
		cin>>s;
	//	while(gcd)
		n=0;
		for(int i=0;i<s.size();i++)
		{
			n=n*10+s[i]-'0';
		}
	//	printf("n===%d \n",n);
		p=0;
		for(int i=0;i<s.size();i++)
		{
			p+=s[i]-'0';
		}
		ll k=__gcd(n,p);
		if(k>1) 
		{
			cout<<n<<endl;
			continue;
		}
		//printf("k===%d \n",k);
		for(int i=1;i<=2;i++)
		{
			n++;
			s=to_string(n);
			p=0;
			for(int i=0;i<s.size();i++)
			{
			p+=s[i]-'0';
			}
			 k=__gcd(n,p);
			 if(k>1) break;
		} 
		cout<<n<<endl;
	}
	return 0;
 } 

B. Box Fitting

题意
给定一个长度位W的容器,高度可以无限延伸。然后给n个,长度为wi的小箱子,每个小箱子高度都是1。求把这些箱子装进容器的最短高度,且箱子不能旋转。

思路:

(贪心)
1.既然要高度最短,那么最好就是每层长度都装满,最好不要浪费空间。从最大的开始装。
2.如果只是单单这样,那么一定会超时。然后题目讲到w数组的范围是1e6,并且每个wi都是2的幂次,那么,2^20=1E6+ ,也就是说,wi的情况最多有20种,在遍历的时候只要 i<=19就可以了。
3.同时,map记录每个箱子的个数,当箱子个数为0时候,就可以退出循环。
4.我这里的代码是每次遍历就算一次,把2^i 预先处理出来会更快。

AC代码

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int N=1e5+10;
typedef long long ll;
ll a[N];
map<ll,int> mp;
ll t;
ll n,m;//m是边长 
int dfs(ll deep,ll sum)
{
	if(sum==0) return deep;
	ll res=m;
	for(int i=19;i>=0;i--)
	{
		ll x=pow(2,i);
	//	printf("x===%d \n",x);
		while(mp[x]>0&&res>=x)
		{
		//	printf("进来的x===%d \n",x);
			res-=x;
			mp[x]--;
			sum--;
		//	printf("sum===%d \n",sum);
		}
		if(res==0) break;
	}
	dfs(deep+1,sum);
	
}
int main()
{
	IOS
	cin>>t;
	while(t--)
	{
		mp.clear();
		cin>>n>>m;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			mp[a[i]]++;
		}
	//	sort(a+1,a+1+n);
		ll ans=dfs(1,n);
		cout<<ans-1<<endl;
	}
	return 0;
	
}

C. Planar Reflections

题意:一个粒子寿命为k,然后要穿过n个板,每穿过n个板,板会反射出k-1寿命的粒子,向反方向。然后这个粒子穿过板子的时候也会执行和上面相同的操作。 问:最终有多少个粒子?

思路(DP,动态规划):

1.设f[i][j]为寿命为i的粒子,穿过j个板,所产生的粒子的个数。
2.由样例可以得出,f[i][j]由两部分组成
(1)原来从前面穿过来的粒子个数,有多少个穿过来,就有多少反弹。很明显f[i][j-1]
(2)产生的新粒子的个数,即反弹从后方来的粒子产生新的粒子的个数。那么这个数,就是在寿命为i-1,也就是前面一个粒子,在j的后面所有的板子产生的个数,那么就是f[i-1][n-j
3.所以,得出递推公式 f[i][j]=f[i][j-1]+f[i-1][n-j] ,答案为f[k][n]。
4.初始化,寿命为1的粒子,穿过每个板子,都是1。
5.如果没有板子,任何寿命的都是1.

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
const long long mod=1e9+7;
int t;
int n,k;
long long f[N][N];
int main()
{
	cin>>t;
	while(t--)
	{
		cin>>n>>k;
	//	memset(f,0,sizeof(f));
		//f[1]=k;
		long long ans=1;
		for(int i=1;i<=n;i++)
		{
			f[1][i]=1;
		}
		for(int i=1;i<=k;i++) f[i][0]=1;
		for(int i=1;i<=k;i++)
		{
			for(int j=1;j<=n;j++)
			{
				f[i][j]=(f[i][j-1]+f[i-1][n-j])%mod;
			}
		}
		
		cout<<f[k][n]<<endl;
	}
	return 0;
 } 

D. Bananas in a Microwave

题意:不好讲自己看

思路:
1.首先想到的肯定是暴力的解法,对于每一次的i,让j从(0—m),更新j+x的次数,那么这种复杂度是O(nmm),肯定是会超时的,所以要选择暴力优化

除了第一次,每一次要加或者乘的时候,也就是遍历j从0到m的过程中,这个J之前一定要出现过

遍历 k从0到y的时候,也就是加的次数或者乘的次数,不能超过最大次数

实现方法:开两个数组,一个记录之前有没有出现过,一个记录这一次中被算了几次

细节:最好不要用ceil 会出错?不知道为什么,希望有大神告诉我。用ceil 会WA, 最好的方法是 X+B-1/B 这种方式,让X向上取整。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long ll;
ll dp[N],d[N];
ll n,m;
void solve()
{
	cin>>n>>m;
	memset(dp,-1,sizeof(dp));
	ll B=1e5;
	dp[0]=0;
	for(int i=1;i<=n;i++)
	{
		ll t,x,y;
		cin>>t>>x>>y;
		memset(d,0,sizeof(d));
		for(int j=0;j<m;j++)
	{
		
		if(dp[j]!=-1)
		{
			if(d[j]==y) continue;
			ll k;
			if(t==1) k=j+(B-1+x)/B;
			else k=(j*x+B-1)/B;
			if(k>m) continue;
			if(dp[k]==-1)
			{
				dp[k]=i;
				d[k]=d[j]+1;
			}
		}
	}
	}
	
	for(int i=1;i<=m;i++) cout<<dp[i]<<" ";
 } 
 
 int main()
 {
 	solve();
 	return 0;
 }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值