Codeforces Round #647 (Div. 2)

A:判断a,b之间是否有倍数关系,没有输出-1。求出a,b之间的倍数cnt,观察该倍数是否为2的幂次,如果不是输出-1。如果2^x == cnt。按照8,4,2的顺序依次把x取完.

#include<bits/stdc++.h>
using namespace std;
#define N 2010
#define maxn (N + 10)
#define maxm (N * 2)
typedef long long ll;
const ll INF = (1e7);
int main(){
    int t;scanf("%d",&t);
    while(t--){
        ll a,b;scanf("%lld%lld",&a,&b);
        ll cnt = 0;
        int flag = 0;
        if(a % b == 0){
            cnt = a / b;flag = 1;
        }
        if(b % a == 0){
            cnt = b / a;flag = 1;
        }
        int n2 = 0;
        while(cnt > 1){
            if(cnt % 2 != 0){
                flag = 0;break;
            }
            cnt /= 2;n2++;
        }
        ll ans = 0;
        if(!flag){
            ans = -1;
        }
        else{
            ans += n2 / 3;n2 %= 3;
            ans += n2 / 2;n2 %= 2;
            ans += n2;
        }
        printf("%lld
",ans);
    }
    return 0;
}

B:对于每一个si,判断二进制位j是否为1,唯一则bits[j]++。容易发现,除了bits[j] * 2 == n的情况,其他情况答案ans在第j位只能取0。所以记录下所有符合bits[j] * 2 == n的位数。然后dfs找到最小答案。

#include<bits/stdc++.h>
using namespace std;
#define N 2010
#define maxn (N + 10)
#define maxm (N * 2)
typedef long long ll;
const ll INF = (1e7);
int s[maxn];
int vis[maxn];
int bits[40];
int b[maxn],bn;
int n,ans;
void dfs(int idx,int cnt){
    if(!idx){
        if(!cnt)return;
        for(int i = 1;i <= n;i++){
            vis[cnt ^ s[i]]--;
        }
        int flag = 1;
        for(int i = 1;i <= n;i++){
            if(vis[s[i]] != 0){
                flag = 0;break;
            }
        }
        if(flag){
            ans = cnt;
            return;
        }
        for(int i = 1;i <= n;i++){
            vis[s[i]] = 1;
        }
        return;
    }
    dfs(idx - 1,cnt);
    if(ans)return;
    dfs(idx - 1,cnt | (1<<b[idx]));
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
        memset(bits,0, sizeof(bits));
        memset(vis,0, sizeof(vis));
        scanf("%d",&n);
        for(int i = 1;i <= n;i++){
            scanf("%d",&s[i]);
            vis[s[i]]++;
            for(int j = 0;j <= 10;j++){
                if(s[i]&(1<<j)){
                    bits[j]++;
                }
            }
        }
        ans = 0;
        bn = 0;
        for(int i = 0;i <= 10;i++){
            if(bits[i] * 2 == n){
                b[++bn] = i;
            }
        }
        dfs(bn,0);
        if(!ans)ans = -1;
        printf("%d
",ans);
    }
    return 0;
}

C:容易发现1-2^x的和为2^(x+1)-1,所以从高位向低位遍历。例如101010010,当遍历到左边第一个1时,求出1 - 100000000的和,当遍历到第二个1时,求出100000001 - 101000000的和,因为前边的位数异或值为零,所以等价于求1 - 1000000的和。所以每一个为1的位数加上相应的前缀和就行。

#include<bits/stdc++.h>
using namespace std;
#define N 2010
#define maxn (N + 10)
#define maxm (N * 2)
typedef long long ll;
const ll INF = (1e7);
int s[maxn];
int vis[maxn];
int bits[40];
int b[maxn],bn;
int n,ans;
void init(){
    ll ans = 0;
    for(ll i = 1;i <= N;i++){
        ll x = (i^(i - 1));
        for(int j = 0;j < 32;j++){
            if(x & (1<<j))ans++;
        }
        printf("i = %lld ans = %lld
",i,ans);
    }
}
int main(){
    //init();
    int t;scanf("%d",&t);
    while(t--){
        ll n;scanf("%lld",&n);
        ll ans = 0;
        for(ll i = 61;i >= 0;i--){
            if(n & (1ll<<i)){
                ans += (1ll<<(i + 1)) - 1;
            }
        }
        printf("%lld
",ans);
    }
    return 0;
}

D:容易发现,topic小的blog必须先放,每一个blog的能取tp,只有1-(tp-1)它的邻居都有,且它没有话题为tp的邻居。

#include<bits/stdc++.h>
using namespace std;
#define N 500010
#define maxn (N + 10)
#define maxm (N * 2)
#define pb push_back
typedef long long ll;
const ll INF = (1e7);
struct blogs{
    int tp,id;
}b[maxn];
vector<int> vc[maxn];
int oup[maxn],on;
int hp[maxn],col[maxn];
bool cmp(blogs x,blogs y){
    return x.tp < y.tp;
}
int main(){
    //init();
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1;i <= m;i++){
        int u,v;scanf("%d%d",&u,&v);vc[u].pb(v);vc[v].pb(u);
    }
    for(int i = 1;i <= n;i++){
        scanf("%d",&b[i].tp);b[i].id = i;
    }
    sort(b + 1,b + 1 + n,cmp);
    on = 0;
    int flag = 1;
    for(int i = 1;i <= n;i++){
        oup[++on] = b[i].id;int u = b[i].id;

        int bn = 0;
        for(auto v:vc[u]){
            if(col[v])hp[++bn] = col[v];
        }
        sort(hp + 1,hp + 1 + bn);
        int cn = (bn > 0);
        for(int j = 1;j < bn;j++){
            if(hp[j] != hp[j + 1])cn++;
        }
        //printf("u = %d cn = %d
",u,cn);
        if(b[i].tp == hp[bn]){
            flag = 0;break;
        }
        if(b[i].tp != cn + 1){
            flag = 0;break;
        }
        col[u] = b[i].tp;
    }
    if(on < n)flag = 0;
    if(flag){
        for(int i = 1;i <= n;i++)printf("%d%c",oup[i],(i == n ? '
' : ' '));
    }
    else{
        printf("-1
");
    }
    return 0;
}

E:我们容易发现:这个差值一定是p的倍数。当从大向小遍历时,可以发现p^ki一定是前面差值 (op[i] = 1 或 -1) sum(op[1]*(p^k[1]) + op[2]*(p^k[2])+……+op[i-1]*(p^k[i-1])) 的因子。所以sum>0时直接减去p^ki,sum = 0,加上p^ki。另外p,k都很大,需要判断差值是为(1e9 + 7)的倍数还是为0,方法是取另一个大质数模差值,如果两个都等于0,说明差值为0.

#include<bits/stdc++.h>
using namespace std;
#define N 1000010
#define maxn (N + 10)
#define maxm (N * 2)
#define pb push_back
typedef long long ll;
const ll INF = (1e7);
const ll mod1 = ((1e9) + 7);
const ll mod2 = ((1e9) + 37);
ll ki[maxn];
ll f_pow(ll x,ll p,ll mod){
    ll ans = 1;
    while(p){
        if(p % 2 == 1){
            ans *= x;ans %= mod;
        }
        x *= x;x %= mod;p /= 2;
    }
    return ans;
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
        ll n,p;scanf("%lld%lld",&n,&p);
        for(int i = 1;i <= n;i++)scanf("%lld",&ki[i]);
        sort(ki + 1,ki + 1 + n);
        ll ans1 = 0,ans2 = 0;
        for(int i = n;i >= 1;i--){
            if(ans1 == 0 && ans2 == 0){
                ans1 += f_pow(p,ki[i],mod1);
                ans2 += f_pow(p,ki[i],mod2);
            }
            else{
                ans1 -= f_pow(p,ki[i],mod1);ans1 = (ans1 + mod1) % mod1;
                ans2 -= f_pow(p,ki[i],mod2);ans2 = (ans2 + mod2) % mod2;
            }
        }
        printf("%lld
",ans1);
    }

    return 0;
}
原文地址:https://www.cnblogs.com/cleanerhgf/p/13049100.html