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)
(k∗z,k∗z)后,先手不能进行其他动作
(
(
k
∗
z
+
k
,
k
∗
z
)
或
(
k
∗
z
,
k
∗
z
+
k
)
)
((k*z+k,k*z)或(k*z,k*z+k))
((k∗z+k,k∗z)或(k∗z,k∗z+k)),那么后手必赢。
如果可以到达 ( ( k ∗ z + k , k ∗ z ) 或 ( k ∗ z , k ∗ z + k ) ) ((k*z+k,k*z)或(k*z,k*z+k)) ((k∗z+k,k∗z)或(k∗z,k∗z+k))这两个点,无论后手第一步怎么走 ( 2 ∗ k , 0 ) (2*k,0) (2∗k,0)或 ( k , k ) (k,k) (k,k)或 ( 0 , 2 ∗ k ) (0,2*k) (0,2∗k)先手都能到达这两个点。
但是题解的迭代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
(k∗z)2+(k∗z)2<=R∗R
得到
z
=
R
∗
R
2
∗
k
2
z = \sqrt\frac{R*R}{2*k^2}
z=2∗k2R∗R
然后直接判断即可
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,n−1] 的一个数组,现在要求通过有限次操作确定下来这个数组:
询问
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=(a⊕b)+2∗(a&b)
a
⊕
b
a \oplus b
a⊕b
=
=
=
a
⊕
c
a \oplus c
a⊕c
⇒
\Rightarrow
⇒
b
=
c
b=c
b=c
n
=
2
k
,
a
⊕
b
n=2^k,a \oplus b
n=2k,a⊕b
=
=
=
n
−
1
n-1
n−1 则
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 a⊕b = = = n − 1 n-1 n−1 ,所以我们可以找到异或值为 n − 1 n-1 n−1的 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=(a⊕b)+2∗(a&b)(重点)
a
⊕
b
a \oplus b
a⊕b
=
=
=
a
⊕
c
a \oplus c
a⊕c
⇒
\Rightarrow
⇒
b
=
c
b=c
b=c
n
=
2
k
,
a
⊕
b
n=2^k,a \oplus b
n=2k,a⊕b
=
=
=
n
−
1
n-1
n−1 则
a
&
b
=
0
a \& b=0
a&b=0
而且异或是最好用来求值的。
晚了,洗洗睡…
今天打牛客巅峰赛抽到一件牛客卫衣,开心ing