CodeCraft-21 and Codeforces Round #711 (Div. 2)A-D题解
Posted 尘封陌路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
以上是关于CodeCraft-21 and Codeforces Round #711 (Div. 2)A-D题解的主要内容,如果未能解决你的问题,请参考以下文章
CodeCraft-21 and Codeforces Round #711 (Div. 2) A,B,C题题解
CodeCraft-21 and Codeforces Round #711 (Div. 2)A-D题解
CodeCraft-21 and Codeforces Round #711 (Div. 2) D. Bananas in a Microwave
Codeforces - 1191E - Tokitsukaze and Duel - 博弈论