CodeCraft-21 and Codeforces Round #711 (Div. 2)(贪心,二分,dp)

A. GCD SUM

本题题意是求该数和该数各数位相加的gcd。找到最小的大于等于该数的gcd不为1的值即可。

由于被3整除的数,其各数位相加也被3整除。故每3个数一定有一个满足条件。故直接暴力计算即可。

AC代码如下:

#include <iostream>
#include <vector>
#include<algorithm>
#include<string>
using namespace std;
typedef long long ll;
int t;
ll n;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%lld",&n);
        for(ll i=n;;i++){
            ll temp=i;
            int mod1=0;
            while(temp){
                mod1+=temp%10;
                temp/=10;
            }
            if(gcd(i,mod1)!=1){
                printf("%lld\n",i);
                break;
            }
        }
    }
    return 0;
}

B.Box Fitting(贪心,二分)

本题的题意是塞高度为1,宽度为2的幂的箱子。在给定w宽度的大箱子中最低需要多高。

我们可以贪心的构造。先放最大的,再将能放入的最大的箱子放入。

即不断放入满足小于剩余空间的最大宽度的箱子即可。(二分法)

如果没有箱子满足剩余空间了。则高度加1,剩余空间重置为w即可。

#include <iostream>
#include <vector>
#include<algorithm>
#include<string>
#include<set>
#define MAXN 100005
#define MOD 1000000007
using namespace std;
typedef long long ll;
int t,n,w;
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&w);
        multiset<int>st;
        int temp;
        for(int i=0;i<n;i++){
            scanf("%d",&temp);
            st.insert(temp);
        }
        int cnt=1,s=w;
        while(!st.empty()){
            auto it=st.upper_bound(s);
            if(it!=st.begin()){
                it--;
                int val = *it;
                s-=val;
                st.erase(it);
            }else{
                s=w;
                cnt++;
            }
        }
        printf("%d\n",cnt);
    }
    return 0;
}

C. Planar Reflections

(说好的c题以前没有dp的呢呜呜)

首先题解是用了3个状态dp[n][k][d]。表示第n个平面半衰期为k的粒子在往方向d运动时所产生的的粒子数。

其中d代表向左或向右的方向(0/1)。

通过观察题目我们可以发现。一个半衰期的粒子只可能朝一种方向。不可能出现同一个半衰期的粒子朝不同方向进发的情况。故我们可以简化为2维的dp。

即dp[n][k]。表示光强为k且前面共有n个平面要轰击时所产生的粒子总数。

其中dp[n][k]这个值就是我们要求的答案。

对于dp[i][j]。当一堆粒子轰击一块板时。所产生的粒子会反方向生成另一部分。即一共有两部分。

一部分即为原来的粒子且方向不变,且该粒子前面的平面数为i-1个。即dp[i-1][j]。

另一部分为反射所产生的粒子,方向相反,半衰期-1且该粒子前面的平面数为n-i个。即dp[n-i][j-1]。

故递推式即为dp[i][j]=dp[i-1][j]+dp[n-i][j-1];

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[1005][1005],q[100005];//dp[k][n]
int main(){
    ll t,n,k,i,j;
    scanf("%lld",&t);
    while(t--){
        scanf("%lld %lld",&n,&k);
        for(i=0;i<=n;i++)//衰变期为0的粒子的出线个数为0 
            dp[0][i]=0;
        for(i=1;i<=k;i++)//前面有0块板的话,无论k如何,都只有1个光线(因为没反弹 
            dp[i][0]=1; 
        for(i=1;i<=k;i++){
            for(j=1;j<=n;j++){
                dp[i][j]=dp[i][j-1]+dp[i-1][n-j];
                dp[i][j]%=1000000007;
            }
        }
        printf("%lld\n",dp[k][n]);
    }
    return 0;
}

 

posted @ 2021-03-30 16:42  mikku  阅读(49)  评论(0)    收藏  举报