Codeforces Round #647 (Div. 2) - Thanks, Algo Muse!(A~D)

A. Johnny and Ancient Computer(因子拆分)

分析

  • 题意
  1. 给我们两个数a、b,现在我们我们可以对 a来了进行一些系列的x2 、x4、 x8、 /2 、/4、 /8 等运算操作,问我们通过一些这样的操作以后能否把a变成b,如果能输出需要的最小次数,否则输出-1
  • 分析
  1. 这个题中既可能有乘法 又有 除法操作,我们可能 在输入a、b的之后,如果 a < b的话,我们交换二者的值,令a始终保持较大值,这样我们只需要对a进行 除法操作了,如果 对a进行 /2 /4 /8的操作之后要想得到最终结果 a == b ,那我们可以令c = a / b(这里要确保 a % b == 0),这样我们依次从c中拆分出尽可能多的 8、在拆分尽可能多的4、最后拆分出尽可能对2 ,这样拆分完之后如果剩下的数不是1的话,直接输出-1,否则的话答案就是拆分出 8,4,2的总共数量

代码

#include 
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod 998244353

int br[10];
int ar[5];

int main()
{
    /* fre(); */
    int T;
    scanf("%d\n", &T);
    ar[1] = 8, ar[2] = 4, ar[3] = 2;
    while(T --)
    {
        ll a, b;
        scanf("%lld %lld", &a, &b);
        if(a < b) swap(a, b);
        if(a % b)
        {
            printf("-1\n");
            continue;
        }

        ll c = a / b;
        memset(br, 0, sizeof(br));
        for(int i = 1; i <= 3; i ++)
        {
            while(c % ar[i] == 0)
            {
                c /= ar[i];
                br[ar[i]] ++;
            }
        }
        if(c != 1)
        {
            printf("-1\n");
            continue;
        }
        printf("%d\n", br[2] + br[4] + br[8]);
    }

    return 0;
}

B. Johnny and His Hobbies(暴力)

分析

  • 题意
  1. 给我们s个数让我们照出一个最小正整数k,是s个数都 异或k 得到的值形成一个集合a,要求a与s中所包含的元素完全相同,求这个k
  • 分析
  1. 由于数据范围比较小,我们直接暴力求解k的最合适值

代码

#include 
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod 998244353

const int mxn = 1e3 + 100;
int ar[mxn];
int br[mxn];
int cr[mxn];

int main()
{
    /* fre(); */
    int T;
    scanf("%d\n", &T);
    while(T --)
    {
        memset(br, 0, sizeof(br));
        int n;
        scanf("%d\n", &n);
        for(int i = 1; i <=n; i ++)
            scanf("%d", &ar[i]), br[ar[i]] = 1;
        int ans = 0;
        for(int i = 1; i <= 1024; i ++)
        {
            memset(cr, 0, sizeof(cr));
            int fg = 1;
            for(int j = 1; j <= n; j ++)
            {
                int t = (ar[j] ^ i);
                if(++ cr[t] >= 2)
                {
                    fg = 0;
                    break;
                }
            }
            if(fg == 0)
                continue;

            for(int j = 0; j <= 1024; j ++)
            {
                if(br[j] != cr[j])
                {
                    fg = 0;
                    break;
                }
            }
            if(fg)
            {
                ans = i;
                break;
            }
        }

        if(ans == 0)
            printf("-1\n");
        else
            printf("%d\n", ans);
    }

    return 0;
}

C. Johnny and Another Rating Drop

分析

  • 分析

000
001
010
011
100
101

  1. 因为二进制是逢二进一,所以我们依次观察二进制的最地位到高位发现,
  2. 对于 二进制值倒数第1位,这一位对答案的贡献是 n
  3. 对与 二进制的倒数第2位,这一位对答案的贡献是 n / 2
  4. 对于 二进制的倒数第3位,这一位对答案的贡献是 n / 4
  5. 综上 二进制的倒数第i位,对答案的贡献是 n / 2 i − 1 n/2^{i-1} n/2i1,
  6. 所以 答案 ans = n/1 + n/2 + n/4 …
  • 还有一种方法也是规律,规律是:2*n - 二进制中1的数量 =ans,,,这个规律为什么对,我也无法解释,但 确实ac了

代码一

#include 
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod 998244353
const int mxn = 1e6 + 100;

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        ll n, i = 1, ans = 0;
        scanf("%lld\n", &n);
        ll now = n;
        while(now)
        {
            ans += n / i;
            i *= 2;
            now >>= 1;      
        }
        printf("%lld\n", ans);
    }



    return 0;
}

代码二

#include 
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod 998244353

const int mxn = 1e3 + 100;

int main()
{
    /* fre(); */
    int T;
    scanf("%d\n", &T);
    while(T --)
    {
        ll n, t;
        scanf("%lld", &n);
        t = n;
        ll ct = 0;
        while(n)
        {
            if(n & 1) ct ++;
            n >>= 1;
        }
        printf("%lld\n", t * 2 - ct);
    }

    return 0;
}

D. Johnny and Contribution(模拟+贪心)

分析

  • 题意
  1. 给我们一个有n个节点m边的无向图,每个节点有一个 1~n的目标权值,然后我们对每个节点进行染色(给这个节点赋上一个 1~n的权值),对于某个节点我要染色的规则是,与当前节点相邻的节点中没有出现过的颜色(权值数字)中最小的那个权值数字我赋值给当前的 节点,通过这样的染色操作之后,如果每个节点的新权值与 目标权值都先相同的话,输出染色节点的顺序,否则输出-1
  • 分析
  1. 贪心,易得我们应该按照期望从小到大涂色,首先我们包期望为1的节点u都涂掉,然后判断与其直接相连的节点v 如果如果它的期望也为1,我们就把v的期望颜色++,
  2. 以此类推,因为是从小开始涂颜色的,所以保证比当前u颜色小的节点都涂过颜色了,接着我就直接判断,只要当前节点u的期望不是原来的颜色,我们就可以直接返回-1,最后 注意一下初始化期望颜色为1

代码

#include 
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod 998244353
const int mxn = 1e6 + 100;

vector<int> e[mxn];
vector<int> col[mxn];
vector<int> ans;
int num[mxn];

int main()
{
    /* fre(); */
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 1, u, v; i <= m; i ++)
    {
        scanf("%d %d", &u, &v);
        e[u].pb(v);
        e[v].pb(u);
    }
    for(int i = 1, t; i <= n; i ++)
    {
        scanf("%d", &t);
        col[t].pb(i);
        num[i] = 1;             //初始的时候,每个节点周围只有一个 自己1个节点
    }

    for(int i = 1; i <= n; i ++)
    {
        for(auto u : col[i])
        {
            if(num[u] != i) printf("-1\n"), exit(0);
            for(auto v : e[u])
                if(num[v] == i) num[v] ++;
            ans.pb(u);
        }
    }

    for(auto i : ans) printf("%d ", i);

    return 0;
}

你可能感兴趣的:(Codeforces)