Codeforces Round #685 (Div. 2) D,E

Codeforces Round #685 (Div. 2)

失踪人口回归…

D. Circle Game

思维难度:4
算法难度:0
代码难度:3

题目大意:

t t t组数据 ( t < = 100 ) (t<=100) (t<=100)
给你一个半径 d d d和步数 k k k,你最开始在原点 ( 0 , 0 ) (0,0) (0,0)每次可以让 x x x坐标增加 k k k,或者 y y y坐标增加 k k k
两人轮流走,求谁最后不能走了,谁就输了,都是最优博弈
输的条件为下次走的坐标 ( x , y ) (x,y) (x,y)都满足 x 2 + y 2 > d 2 x_2+y_2>d_2 x2+y2>d2

思路:

简单博弈题。
首先得注意到y=x这条线。
无论先手怎么选择,后手都能让它回到y=x这条线上,所以如果最后一次行动在线上 ( k ∗ z , k ∗ z ) (k*z,k*z) (kz,kz)后,先手不能进行其他动作 ( ( k ∗ z + k , k ∗ z ) 或 ( k ∗ z , k ∗ z + k ) ) ((k*z+k,k*z)或(k*z,k*z+k)) ((kz+k,kz)(kz,kz+k)),那么后手必赢。

如果可以到达 ( ( k ∗ z + k , k ∗ z ) 或 ( k ∗ z , k ∗ z + k ) ) ((k*z+k,k*z)或(k*z,k*z+k)) ((kz+k,kz)(kz,kz+k))这两个点,无论后手第一步怎么走 ( 2 ∗ k , 0 ) (2*k,0) (2k,0) ( k , k ) (k,k) (k,k) ( 0 , 2 ∗ k ) (0,2*k) (0,2k)先手都能到达这两个点。

但是题解的迭代emm,我自己写是超时的
代码:(TLE 5)

// Author:slime
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 10500;
const ll mod = 1e9 + 7;
const ll inf = 0x3f3f3f3f;
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
 
int main() {
    int T;
    scanf("%d",&T);
    while (T--) {
        ll t, d;
        scanf("%lld %lld",&d,&t);
        ll tmp = t;
        int cnt = 0;
        int x = 0, y = 0;
        int flag_hou = -1, flag_xian = -1;
        for (int i = 1;; i++) {
            if (x*x+y*y <= d * d) {
                x += t;
            }
            if (x*x+y*y <= d * d) {
                y += t;
            } else {
                break;
            }
        }
        if (x != y)
            puts("Utkarsh");
        else
            puts("Ashish");
    }
}

所以数学推了一下,一次性得到y=x线上最远的点
公式大致是
( k ∗ z ) 2 + ( k ∗ z ) 2 < = R ∗ R (k*z)^2+(k*z)^2<=R*R (kz)2+(kz)2<=RR
得到 z = R ∗ R 2 ∗ k 2 z = \sqrt\frac{R*R}{2*k^2} z=2k2RR
然后直接判断即可
AC代码

// Author:slime
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 10500;
const ll mod = 1e9 + 7;
const ll inf = 0x3f3f3f3f;
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
 
int main() {
    int T;
    scanf("%d",&T);
    while (T--) {
        ll t, d;
        scanf("%lld %lld",&d,&t);
        ll k=t;        
        ll x = ll(sqrt(d*d*1.0/(k*k*2.0)));
        if (x*x*k*k+(x+1)*(x+1)*k*k>d*d)
            puts("Utkarsh");
        else
            puts("Ashish");
    }
}

反思:
对于博弈,应往一种固定形式的思维去想,至于是什么形式,就得分析题目,找最有帮助的情况或者条件分析。

E2 - Bitwise Queries (Hard Version)

思维难度:6
算法难度:2
代码难度:3
题目大意:
题目大意:给出一个长度为 n n n n n n 保证了是 2 2 2 的幂次),每个数的范围在 [ 0 , n − 1 ] [ 0 , n - 1 ] [0,n1] 的一个数组,现在要求通过有限次操作确定下来这个数组:
询问 a [ i ] a[ i ] a[i] ⊕ \oplus a [ j ] a[ j ] a[j]的答案
询问 a [ i ] a[ i ] a[i] ∣ | a [ j ] a[ j ] a[j] 的答案
询问 a [ i ] a[ i ] a[i] & \& & a [ j ] a[ j ] a[j] 的答案
思路:
首先应该知道
a + b = ( a ⊕ b ) + 2 ∗ ( a & b ) a + b = (a \oplus b) + 2 * (a \& b) a+b=(ab)+2(a&b)
a ⊕ b a \oplus b ab = = = a ⊕ c a \oplus c ac ⇒ \Rightarrow b = c b=c b=c
n = 2 k , a ⊕ b n=2^k,a \oplus b n=2k,ab = = = n − 1 n-1 n1 a & b = 0 a \& b=0 a&b=0
那么我们可以快乐解题了
先求出一个数(默认为第1个数)和其他所有的数的异或。
对于一个数组,可以分成每个都不同,和至少有两个相同的情况。

  • 当有至少两个相同的时候:
    则上面求的异或会有两个相同的值(假设为 n u m [ i ] num[i] num[i], n u m [ j ] num[j] num[j]),然后我们就可以通过 n u m [ i ] & n u m [ j ] num[i]\&num[j] num[i]&num[j]得到 i i i j j j的值。然后 n u m [ 1 ] num[1] num[1]的值,然后得到所有的值。
  • 当每个都不同的时候:
    a ⊕ b a \oplus b ab = = = n − 1 n-1 n1 ,所以我们可以找到异或值为 n − 1 n-1 n1 n u m [ i ] num[i] num[i],则 n u m [ 1 ] & n u m [ i ] = 0 num[1] \& num[i]=0 num[1]&num[i]=0
    然后我们就可以得到 n u m [ 1 ] + n u m [ i ] num[1]+num[i] num[1]+num[i]的值
    之后我们只需要再用两次查询得到 n u m [ 1 ] & n u m [ j ] num[1]\&num[j] num[1]&num[j] n u m [ i ] & n u m [ j ] num[i]\&num[j] num[i]&num[j]
    进而得到 n u m [ 1 ] + n u m [ j ] num[1]+num[j] num[1]+num[j] n u m [ i ] + n u m [ j ] num[i]+num[j] num[i]+num[j]即可求出 n u m [ 1 ] num[1] num[1]

ac代码:

// Author:slime
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 10500;
const ll mod = 1e9 + 7;
const ll inf = 0x3f3f3f3f;
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()

#ifdef ONLINE_JUDGE
#define debug(...) 13
#else
#include "debug.cpp"
#endif

int main() {
#ifdef ONLINE_JUDGE
#else
// freopen("in.txt","r",stdin);
#endif
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    int n;
    cin >> n;
    vector<int> Xor(n + 1);
    unordered_map<int, int> mp;
    int dx = -1, dy = -1;
    mp[0] = 1;
    for (int i = 2; i <= n; i++) {
        cout << "XOR " << 1 << " " << i << endl;
        cin >> Xor[i];
        if (mp.find(Xor[i]) != mp.end() && dx == -1 && dy == -1) {
            dy = mp[Xor[i]];
            dx = i;
        }
        mp[Xor[i]] = i;
    }
    if (dx != -1 && dy != -1) {  //第一种情况
        cout << "AND " << dx << " " << dy << endl;
        int aj;
        cin >> aj;
        int a1 = Xor[dx] ^ aj;
        cout << "!"
             << " " << a1;
        for (int i = 2; i <= n; i++) {
            cout << " " << (Xor[i] ^ a1);
        }
        cout << endl;
    } else {  //第二种情况
        int id=-1;
        for (int i = 2; i <= n; i++) {
            if (Xor[i] == n - 1) {
                id = i;
            }
        }
        //a1&aid=0
        //a1+aid=(a1^aid)-2*(a1&aid)
        int sum1=n-1;
        int idd=(id==2?3:2);
        int And1,And2,XOR2;
        cout << "AND " << 1 << " " << idd << endl;
        cin>>And1;
        cout << "AND " << idd << " " << id << endl;
        cin>>And2;
        XOR2=Xor[idd]^Xor[id];        
        int sum2=Xor[idd]+2*And1;
        int sum3=XOR2+2*And2;
        int a1=(sum2+sum1-sum3)/2;
        cout << "!"
             << " " << a1;
        for (int i = 2; i <= n; i++) {
            cout << " " << (Xor[i] ^ a1);
        }
        cout << endl;
    }
}

反思:
对于位运算题,应该记住下面这几个定理
a + b = ( a ⊕ b ) + 2 ∗ ( a & b ) a + b = (a \oplus b) + 2 * (a \& b) a+b=(ab)+2(a&b)重点
a ⊕ b a \oplus b ab = = = a ⊕ c a \oplus c ac ⇒ \Rightarrow b = c b=c b=c
n = 2 k , a ⊕ b n=2^k,a \oplus b n=2k,ab = = = n − 1 n-1 n1 a & b = 0 a \& b=0 a&b=0
而且异或是最好用来求值的。

晚了,洗洗睡…
今天打牛客巅峰赛抽到一件牛客卫衣,开心ing

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值