Codeforces Round #383 (Div. 2) 题解

【题目地址】点击打开链接

【A】求1378的n次方的最后一位,一种方法是发现他是以4为周期的答案,另外一种直接快速幂了。

【B】给了n个数,求两个数的异或和为x的对数。 a[i] ^ a[j] = x, 对于每个 a[i]来说就相当于统计下 a[j]^x的个数。然后还要特判0,这里挂了一发。

【C】SCC+lcm。注意这个题会爆int。注意如果求出来的scc的长度是偶数,应该先除以2再求最小公倍数。

const int N = 2000;
typedef long long LL;
int to[N], vis[N];

LL lcm(LL a, LL b) {
    return a / __gcd(a, b) * b;
}

int main() {
    int n; scanf("%d", &n);
    memset(vis, 0, sizeof vis);
    for(int i = 1; i <= n; i++) scanf("%d", &to[i]);
    LL ans = 1;
    for(int i = 1; i <= n; i++) if(!vis[i]) {
        int k = i, s = 0;
        do {
            vis[k] = true;
            s++;
            k = to[k];
        } while(!vis[k]);
        if(k != i) {
            puts("-1");
            return 0;
        }
        if(s & 1) ans = lcm(ans, s);
        else ans = lcm(ans, s / 2);
    }
    printf("%I64d\n", ans);
    return 0;
}

【D】用并查集维护朋友关系,对于一组朋友来说,可以选择其中的一个朋友,或者整组。再把每一组当作物品,进行求解背包问题。

int fa[1200];
LL n, m, k, but[1200], we[1200], dp[1200], grbut[1200], grwe[1200];
vector<int>g[1200];
int Find(int x){
    if(x == fa[x]) return x;
    else return fa[x] = Find(fa[x]);
}
int main()
{
    for(int i = 0; i < 1200; i++) fa[i] = i;
    //emset(dp, -1, sizeof(dp));
    memset(grbut, 0, sizeof(grbut));
    memset(grwe, 0, sizeof(grwe));
    scanf("%lld%lld%lld", &n,&m,&k);
    for(LL i = 1; i <= n; i++) scanf("%lld", &we[i]);
    for(LL i = 1; i <= n; i++) scanf("%lld", &but[i]);
    for(LL i = 0; i < m; i++){
        int x, y;
        scanf("%d%d", &x,&y);
        int fx = Find(x), fy = Find(y);
        fa[fx] = fy;
    }
    for(LL i = 1; i <= n; i++){
        g[Find(i)].push_back(i);
        grwe[Find(i)] += we[i];
        grbut[Find(i)] += but[i];
    }
    memset(dp, 0, sizeof(dp));
    for(LL i = 1; i <= n; i++){
        if(g[i].size()){
            for(LL j = k; j >= 0; j--){
                for(int l = 0; l < g[i].size(); l++){
                    if(j + we[g[i][l]] <= k){
                        dp[j + we[g[i][l]]] = max(dp[j + we[g[i][l]]], dp[j] + but[g[i][l]]);
                    }
                }
                if(j + grwe[i] <= k){
                    dp[j + grwe[i]] = max(dp[j + grwe[i]], dp[j] + grbut[i]);
                }
            }
        }
    }
    LL ans = -1;
    for(int i = 0; i<= k; i++) ans = max(dp[i], ans);
    printf("%lld\n",ans);
}

【E】首先把2*i和2*i-1连边,然后把男女朋友连边,连边之后会发现要构造的这个关系实际上就是给二分图染色的问题。那么这题就可以a了。

//
//Created by just_sort 2016/12/8
//Copyright (c) 2016 just_sort.All Rights Reserved
//

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace __gnu_pbds;
typedef long long LL;
typedef pair<int, LL> pp;
#define MP(x,y) make_pair(x,y)
const int maxn = 400020;
const int maxm = 1<<12;
const int inf = 0x3f3f3f3f;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>order_set;
//head

int n, col[maxn], boy[maxn], gril[maxn];
vector<int>G[maxn];
bool dfs(int u, int c)
{
    col[u] = c;
    for(int i = 0; i < G[u].size(); i++){
        if(col[G[u][i]] == c) return false;
        if(col[G[u][i]] == 0 && !dfs(G[u][i], 3 - c)){
            return false;
        }
    }
    return true;
}
int main()
{
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        G[2*i-1].push_back(2*i);
        G[2*i].push_back(2*i-1);
        scanf("%d%d", &boy[i],&gril[i]);
        G[boy[i]].push_back(gril[i]);
        G[gril[i]].push_back(boy[i]);
    }
    memset(col, 0, sizeof(col));
    for(int i = 1; i <= 2*n; i++){
        if(col[i] == 0){
            if(!dfs(i, 1)){
                puts("-1\n");
                return 0;
            }
        } 
    }
    for(int i = 1; i <= n; i++){
        printf("%d %d\n", col[boy[i]], col[gril[i]]);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值