以前看见博弈论的题就直接跳过,直到上周河北省赛开始前瞅了两眼白书上的博弈论,发现博弈论不过是dp好像也不难哈.
今天刚好做到一个简单的博弈论
由于我当时对博弈论的了解仅限于博弈论就是dp,所以很兴奋的用dp提交了,然后就TLE在test12了。
#include<bits/stdc++.h>
using namespace std;
int a[100010];
int dp[100010][5];
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
for(int i = 0; i < n; i++){
bool flag = true;
for(int last = (i - 1 + n) % n; last != (i - 1 + n) % n || flag; last = (last - 1 + n) % n){
if(last == (i - 1 + n) % n){
dp[last][1] = 1; dp[last][0] = 0;
}
else{
int pre = (last + 1) % n;
if(a[last] == 1){
dp[last][1] = dp[pre][0];
dp[last][0] = dp[pre][1];
}
else{
dp[last][1] = 1;
dp[last][0] = 0;
}
}
flag = false;
}
printf((dp[i][1] == 1) ? "First\n" : "Second\n");
}
return 0;
}
很明显O(N*N)太大了,我灵机一动,直接改首尾的dp不就优化成O(N)了吗,然后就又WA在test10了。
#include<bits/stdc++.h>
using namespace std;
int a[100010];
int dp[100010][5];
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
for(int last = n - 1; last != -1; last--){
if(last == n - 1){
dp[last][1] = 1; dp[last][0] = 0;
}
else{
int pre = (last + 1) % n;
if(a[last] == 1){
dp[last][1] = dp[pre][0];
dp[last][0] = dp[pre][1];
}
else{
dp[last][1] = 1;
dp[last][0] = 0;
}
}
}
printf((dp[0][1] == 1) ? "First\n" : "Second\n");
int reverse = 0;
for(int i = 1; i < n; i++){
int llast = (i - 2 + n) % n, last = i - 1;
if(a[llast] == 1) reverse = (1 - reverse);
if(reverse){
dp[i][1] = (1 - dp[i][1]);
dp[i][0] = (1 - dp[i][0]);
}
printf((dp[i][1] == 1) ? "First\n" : "Second\n");
}
return 0;
}
冷静了一下,突然发现,这其实并不需要dp,只要谁先在>1的堆是先手谁就必胜。
所以只需要记录下>1堆的位置,每次只需要计算在当前位置前面的第一个堆与当前位置的距离就ojbk了。
由于是个环,莫名其妙的就想到了队列pop后push的骚操作hhh。
写完这段代码我感觉绝对要AC了,结果又WA在test7了。
#include<bits/stdc++.h>
using namespace std;
queue <int > q;
int main(){
int n, x;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &x);
if(x > 1) q.push(i);
}
for(int i = 1; i <= n; i++){
int u = q.front();
if(i == u){
printf("First\n");
q.pop();
q.push(u);
}
else{
int dis = (u - i < 0 ? u - i + n : u - i);
printf((dis % 2 == 1) ? "Second\n" : "First\n");
}
}
return 0;
}
怎么会WA呢??我瞟一眼题面,猛然发现,如果所有堆的size都为1的话,就不会有>1的堆,那么q就为空了,此处应加特判。
#include<bits/stdc++.h>
using namespace std;
queue <int > q;
int main(){
int n, x;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &x);
if(x > 1) q.push(i);
}
if(!q.empty()){
for(int i = 1; i <= n; i++){
int u = q.front();
if(i == u){
printf("First\n");
q.pop();
q.push(u);
}
else{
int dis = (u - i < 0 ? u - i + n : u - i);
printf((dis % 2 == 1) ? "Second\n" : "First\n");
}
}
}
else for(int i = 1; i <= n; i++) printf((n % 2 == 1) ? "First\n" : "Second\n");
return 0;
}
终于AC!罚时真令人绝望