Codeforces Round #565 (Div. 3)简要题解

A. Divide it!

分析:2,3,5互质,直接暴力即可。

#include "bits/stdc++.h"
using namespace std;
int main(){
    int q;
    cin>>q;
    while(q--){
        long long n;
        cin>>n;
        int ans= 0;
        while(n%5==0){
            n=n/5*4;
            ans++;
        }
        while (n%3==0){
            n=n/3*2;
            ans++;
        }
        while(n%2==0){
            n=n/2;
            ans++;
        }
        if(n==1)cout<<ans<<endl;
        else puts("-1");
    }
}

B. Merge it!

分析:直接记录mod3=1,2,0的个数,然后配对就可以了。

#include "bits/stdc++.h"
using namespace std;
int main(){
    int t;
    cin>>t;
    while (t--){
        int n;
        cin>>n;
        int a1,a2,a3;
        a1=a2=a3=0;
        int x;
        for (int i = 0; i < n; ++i) {
            scanf("%d",&x);
            if(x%3==0)a3++;
            if(x%3==1)a1++;
            if(x%3==2)a2++;
        }
        if(a1>a2)swap(a1,a2);
        a3+=a1;
        a3+=(a2-a1)/3;
        cout<<a3<<endl;
    }
}

C. Lose it!

分析:直接线性跑一遍记录个数就可以了。最后n-6*num

#include "bits/stdc++.h"

using namespace std;


int a[500004];

int main() {
    int n;
    cin >> n;
    int a4, a8, a15, a16, a23, a42;
    a4 = a8 = a15 = a16 = a23 = a42 = 0;
    for (int i = 0; i < n; ++i) {
        scanf("%d", &a[i]);
    }
    for (int i = 0; i < n; ++i) {
        if(a[i]==4){
            a4++;
        }
        if(a[i]==8){
            if(a4)a4--,a8++;
        }
        if(a[i]==15){
            if(a8)a8--,a15++;
        }
        if(a[i]==16){
            if(a15)a15--,a16++;
        }
        if(a[i]==23){
            if(a16)a16--,a23++;
        }
        if(a[i]==42){
            if(a23)a23--,a42++;
        }
    }
    printf("%d\n",n-a42*6);
}

D. Recover it!

分析:质数只能引进比自己大的质数,非质数可以引进比自己小的质数或非质数,那么最大的非质数一定是原数组的。

按照这个思路从大的非质数开始找,然后再从小的质数找,用multiset维护一下就可以了。

#include "bits/stdc++.h"

using namespace std;
bool vis[2750132];
int prim[200004];
int cnt ;
int to[200004];
void init(){
    cnt = 1;
    for (int i = 2; i <= 2750131  ; ++i) {
        if(!vis[i])prim[cnt++]=i;
        for (int j = 1; j <= cnt && i* prim[j]<=2750131  ; ++j) {
            vis[i*prim[j]]=1;
            if(i%prim[j]==0)break;
        }
    }
    for (int i = 2; i <= 200000; ++i) {
        if(!vis[i])to[i]=prim[i];
        else {
            for (int j = 1; j <=cnt ; ++j) {
                if(i%prim[j]==0){
                    to[i]=i/prim[j];
                    break;
                }
            }
        }
    }

}

int a[200004];
int b[400004];
bool viss[400004];
int pos;
int main() {
    int n;
    cin >> n;
    pos=1;
    init();multiset<int>s;
    for (int i = 1; i <= 2*n; ++i) {
        scanf("%d",&b[i]);
        s.insert(b[i]);
    }
    sort(b+1,b+1+n+n);
    for (int i = n*2; i >= 1; --i) {
        if(vis[b[i]] && s.count(b[i])){
           a[pos++]=b[i];
           s.erase(s.find(b[i]));
           s.erase(s.find(to[b[i]]));
        }
    }
    while(!s.empty()){
        auto it  = s.begin();
        int x=*it;
        a[pos++]=x;
        s.erase(s.find(to[x]));
        s.erase(s.begin());
    }
    for (int i = 1; i <= n; ++i) {
        printf("%d ",a[i]);
    }
}

E. Cover it!

分析:建图然后枚举点染色,只染相邻的点,染过的点直接跳过。然后判断一下个数输出染色的点或者未染色点。

#include "bits/stdc++.h"

using namespace std;
vector<int>v[200004];
bool vis[200004];
void to(int u){
    for (int i = 0; i < v[u].size(); ++i) {
        vis[v[u][i]]=1;
    }
}
int main() {
    int t;
    cin>>t;
    while(t--){
        int n,m;
        scanf("%d%d",&n,&m);
        int x,y;
        for (int i = 0; i <= n; ++i) {
            v[i].clear();
        }
        memset(vis,0, sizeof(vis));
        for (int i = 0; i < m; ++i) {
            scanf("%d%d",&x,&y);
            v[x].push_back(y);
            v[y].push_back(x);
        }
        int ans=0;
        for (int i = 1; i <= n; ++i) {
            if(!vis[i]){
                ans++;
                to(i);
            }
        }
        if(ans<=n/2){
            printf("%d\n",ans);
            for (int i = 1; i <= n; ++i) {
                if(!vis[i])printf("%d ",i);
            }
        }
        else {
            printf("%d\n",n-ans);
            for (int i = 1; i <= n; ++i) {
                if(vis[i])printf("%d ",i);
            }
        }
        puts("");
    }
}

F. Destroy it!

分析:用dp[i][j]表示第i个回合,已经打出了x张牌且x%10==j,每次打牌的情况只有4种:0,1,2,3,找出每种对应状态的最大的几张牌,递推状态就可以了。

#include "bits/stdc++.h"

using namespace std;
vector<long long> v[200004][4];
long long dp[200004][10];

bool cmp(long long a, long long b) {
    return a > b;
}

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        int k;
        scanf("%d", &k);
        long long c, d;
        for (int j = 0; j < k; ++j) {
            scanf("%lld%lld", &c, &d);
            v[i][c].push_back(d);
        }
        for (int j = 1; j <= 3; ++j) {
            sort(v[i][j].begin(), v[i][j].end(), cmp);
        }
    }
    memset(dp, -1, sizeof(dp));
    dp[0][0] = 0;
    for (int i = 1; i <= n; ++i) {
        int X = v[i][1].size() + v[i][2].size() + v[i][3].size();
        for (int j = 1; j <= 3; ++j) {
            if (X < j)break;
            long long a[3] = {0};
            if (j == 1) {
                if (v[i][1].size())
                    a[0] = max(a[0], v[i][1][0]);
                if (v[i][2].size())
                    a[0] = max(a[0], v[i][2][0]);
                if (v[i][3].size())
                    a[0] = max(a[0], v[i][3][0]);
            } else if (j == 2) {
                if (!(v[i][1].size() > 0 && v[i][1].size() + v[i][2].size() > 1))continue;
                if (v[i][1].size())
                    a[0] = max(a[0], v[i][1][0]);
                else continue;
                if (v[i][2].size())
                    a[1] = max(a[1], v[i][2][0]);
                if (v[i][1].size() > 1)
                    a[1] = max(a[1], v[i][1][1]);
            } else if (j == 3) {
                if (v[i][1].size() < 3)continue;
                for (int k = 0; k < 3; ++k) {
                    a[k] = v[i][1][k];
                }
            }
            sort(a, a + j);
            for (int k = 0; k < 10; ++k)dp[i][k]=max(dp[i][k],dp[i-1][k]);
            for (int k = 0; k < 10; ++k) {
                if (dp[i - 1][k] ==  -1)continue;
                long long sum = 0;
                if (k + j >= 10)for (int l = 0; l < j; ++l)sum += (l == j - 1 ? 2LL * a[l] : a[l]);
                else for (int l = 0; l < j; ++l)sum += a[l];
                dp[i][(k + j) % 10] = max(dp[i][(k + j) % 10], dp[i - 1][k] + sum);
            }
        }
    }
    long long ans = 0;
    for (int i = 0; i < 10; ++i) {
        ans = max(ans, dp[n][i]);
    }
    cout << ans << endl;

}

 

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值