翠竹叶飞
Hello the cruel world.

A 一看到题,不是一道解不定方程的裸题吗,调了好久exgcd。 其实一个for就好了啊

B 一直WA ON TEST 7真是烦,一想会不会是编号太大了,又写了一个map版本,无用。

调了好久好久才发现有几次询问没有读完mmp

C 调了一晚上,又看了数篇题解,终于看懂了QAQ

这是一道博弈论,借助图论/DP帮助完成。

博弈中有3种状态:必胜,必败,不一定

而我们需要将这些状态一直转移以求得结果。

如果A无论怎么移动,使B下一步必胜,则A的现在状态为必败。
如果A可以移动任意一步,使B下一步必败,则A现在的状态为必胜。

没被搜到就不一定。

大致思路就是这样,考虑具体实现。

1.如果从每个状态正着搜,显然不行。只能由终止状态倒着推

2.每个状态记录一下入度,且每次若转移需要判重! 经计算,queue空间为4*n

3.思路要清晰,要清楚我们输出的是什么东西(我昨晚一直思路混乱,多求了很多没用的东西)

4.注意细节,我好粗心好粗心啊

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,b) for (int i=a; i<=b; i++)
typedef long long ll;
using namespace std;
#define N 7005
int n,k[2],s[2][N],dp[2][N]; //1 win  0 loop  -1 lose
int Degree[2][N]; //此时先手者 
struct Node {
    int p,turn;
} q[N<<2],u,v;

inline void read(int &x) {
    x=0; char c=getchar(); int f=1;
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {x=10*x+c-'0'; c=getchar();} x*=f;
}
inline void bfs() {
    int f=0,r=2;
    u.p=1; u.turn=0; q[0]=u; dp[0][1]=-1;
    u.turn=1; q[1]=u; dp[1][1]=-1;
    rep(i,1,n) rep(j,0,1) Degree[j][i]=k[j]; //此时先手者
    while (f!=r) {
        u=q[f++]; int now=u.turn;
        rep(i,1,k[now^1]) { //len!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            int dot=(u.p-s[now^1][i]+n-1)%n+1; //% !!!!!!!!!!
            if (dot==1) continue; //can't be realized!!!!!!!!
            if (dp[now][u.p]==-1) {
                if (dp[now^1][dot]==1) continue;
                dp[now^1][dot]=1;
                v.turn=u.turn^1; v.p=dot;
                q[r++]=v;
            }
            else if (dp[now][u.p]==1) {
            //    if (dp[now^1][dot]==1) continue;    if win,can't lose!!
                if ((--Degree[now^1][dot])==0) {
                    dp[now^1][dot]=-1;
                    v.turn=u.turn^1; v.p=dot;
                    q[r++]=v;
                }
            }
        }
    }
}
int main() {
//    freopen("1.in","r",stdin);
    read(n);
    rep(i,0,1) {read(k[i]); rep(j,1,k[i]) read(s[i][j]);}
    bfs();
    rep(i,0,1) {
        rep(j,2,n)
            if (dp[i][j]==1) printf("Win ");
            else if (dp[i][j]==-1) printf("Lose ");
            else printf("Loop ");
        puts("");
    }
    return 0;
}

 

 D 线段树/虚拟点优化建图

直接建图不可能,这种区间题肯定是裸的线段树

建两棵线段树,每个节点代表一个区间,对于2、3操作,最多连log条边。

第1棵:上到下连边 ;第2棵:下到上连边 

操作2:点到tree1的node连边

操作3:tree2的node到点连边

这个转化挺巧妙的。。

 

自己果然还是菜

posted on 2017-05-25 18:25  翠竹叶飞  阅读(182)  评论(0编辑  收藏  举报