「Codeforces」 Round #779 (Div. 2)

A. Marin and Photoshoot

题目大意

对于给定的 01 01 01串,可以在其中添加若干个 1 1 1,使得任意区间内, 0 0 0 的个数不超过 1 1 1 的个数。

解题思路

对于本题,我们只关心前后距离不超过2的两个0:

  1. 对于010, 不合法,需要在中间再加一个1
  2. 对于100001不合法,需要在两个0中加入两个1
    即: 每两个0之间,至少需要两个1
Code
void solve() 
{
    int n;	string s;	vector<int> v;
    cin >> n >> s;
        
    for (int i = 0; i < n; i++)
        if (s[i] == '0')	v.push_back(i);
        
    int res = 0;
    for (int i = 1; i < v.size(); i++)
        if (v[i] - v[i - 1] <= 2)	res += 3 - (v[i] - v[i - 1]);
        
    cout << res << endl;
}

B. Marin and Anti-coprime Permutation

解题思路

这道题当时模拟了n = 1,2,3的例子才找到规律
证明略.需要的话请看官方题解
如果n奇数,则符合条件的排列数一定为0
如果n偶数,我们只需在奇数位置上放偶数, 偶数位置上放奇数即可
对于偶数情况,可得出一个公式=> r e s = ( ( n / 2 ) ! ) 2 res = ((n / 2)!)^2 res=((n/2)!)2

Code
void solve()
{
    int n; cin >> n;
    if (n & 1)	
    {
        puts("0");
        return;
    } 
    else 
    {
        int m = n / 2, sum = 1;
        for (int i = m; i >= 1; i--)	sum = (sum * i) % mod;  // 求 n/2 的阶乘
        int now = (sum * sum) % mod;  // 求阶乘的平方
        cout << now << endl;
    }
}

C. Shinju and the Lost Permutation (思维)

解题思路

建议看官方题解(其实是懒得描述)
这里只提供一个关键性质:
对于全排列中 n n n 移动后答案为1的情况只有 [ n , . . . . . ] [n,.....] [n,.....]
所以对于给定的数组,其中只能出现一个1,否则就不合法

Code

void solve()
{
    int n;  cin >> n;
    for (int i = 1; i <= n; i++)    cin >> c[i];

    if (count(c + 1, c + 1 + n, 1) != 1) // 只能出现一个1
    {
        puts("NO");
        return;
    }

    vector<int> t, a;
    for (int i = 1; i <= n; i++)  // 把给定的数组变为从1开头,对应于排列【n,...]的情况
    {
        if (c[i] != 1)  t.push_back(c[i]);
        else 
        {
            for (int j = i; j <= n; j++)    a.push_back(c[j]);
            for (auto x : t)    a.push_back(x);
        }
    }

    for (int i = 1; i < a.size(); i++)
        if (a[i] - a[i - 1] > 1) 
        {
            puts("NO");
            return;
        }

    puts("YES");
}

D1. 388535 (Easy Version) (位运算/规律)

题目大意

对于给定的数组 a a a ,你需要找到一个数 x x x ,满足 b i = a i ⊕ x b_i = a_i \oplus x bi=aix后,对 b b b 排序后的结果为 [ 0 , 1 , 2 , 3 , 4 , 5... n ] [0,1,2,3,4,5...n] [0,1,2,3,4,5...n] 。问 x x x 是多少。

解题思路

我们首先可以列出0~7的二进制
分别为

000  0   我们对于每一位进行查看(垂直): 对于第0位:  对于第1位 
001  1                                  1       0
010  2                                  0       0    
011  3                                  1       1
100  4                                  0       1
101  5                                  1       0
110  6                                  0       1    
111  7                                  1       1

可以发现性质: 任意一位的前缀中, 0 0 0 的个数一定大于等于 1 1 1 的个数。
只有满足这个性质才可以构成 b b b数组排序后形成 [ 0 , 1 , 2 , 3 , 4 , 5... n ] [0,1,2,3,4,5...n] [0,1,2,3,4,5...n]这样的连续排列。

所以对于给定的异或后的结果,我们只需要对它的每一位0,1个数进行统计,
如果某一位的1个数大于0个数,就对这一位$\oplus$1, 因为1 ⊕ \oplus 1 = 0;

其实可以反向理解一波,为什么要在这一位上异或一个1? 因为正是因为x这个数上有这个0/1才使得数组 a a a不符合上述性质

Code
void solve()
{
    memset(cnt, 0,sizeof cnt);

    int l, r;   cin >> l >> r;
    for (int i = l; i <= r; i++)
    {
        int x;  cin >> x;
        for (int j = 0; j < 30; j++)    
            cnt[j][x >> j & 1]++;  // 统计每一个数的每一位的0/1个数
    }

    int res = 0;
    for (int i = 0; i < 30; i++)
        if (cnt[i][1] > cnt[i][0])  res += 1 << i; 

    cout << res << endl;
}

TIPS:如果WA了,那一定是精度问题,本人代码头文件不同

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wiz1code(算法号)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值