10.14模拟总结

今天模拟很有趣,你只要写一份AC代码就能顺便用它来与好友进行k子棋和围棋的混合棋(只是不支持悔棋)。

T1.FIR

期望得分100,实际得分64,(如果有subtask是0分)

这就是那道有趣的题。大模拟……

判断赢我的办法是dfs,分别向八个方向搜索,把相对应的两个方向的答案加上看是否有一个符合。

判断死的话,从一个子开始bfs,遇到同颜色子压入队列,如果周围有一口气就能活,如果搜到最后也没有的话就是死了。

判断吃子的话,找这个子四周的子,遇到一个不同颜色的就开始判死,如果死了的话,我们把棋盘那个位置还原。(我的办法是开一个栈记录一下搜到了哪些子)

判断的顺序是:先不合法(那个位置有棋),再判吃子,再判胜利,如果吃不了子判死亡,没死判胜利。

然后本人因为打了vis标记然后……没用,凉凉。而且还忘了一次能吃好几个子,又凉凉。注意棋盘是无限的,所以其实在边上的子是有气的,而且你还杀不死它。

改完之后就好了,同时也看一下std,非常简洁……只用了我一半的码长……

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<utility>
#include<map>
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
using namespace std;
typedef long long ll;
const int M = 100005;
const int N = 10000005;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >='0' && ch <= '9')
    {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
    }
    return ans * op;
}

struct node
{
    int x,y;
};

int n,p,g[1005][1005],stack[1005][3],top,x,y;
int dx[10] = {0,1,1,0,-1,-1,-1,0,1},dy[10] = {0,0,1,1,1,0,-1,-1,-1};
int sx[6] = {0,1,0,-1,0},sy[6] = {0,0,1,0,-1};

bool vis[1005][1005];
queue <node> q;

bool pddie(int x,int y,bool f)
{
    bool flag = 0;
    if(x == 3 && y == 4) flag = 1;
    while(!q.empty()) q.pop();
    q.push((node){x,y});
    while(!q.empty())
    {
        node k = q.front();
        q.pop();
//        if(flag) printf("%d %d\n",k.x,k.y);
        vis[k.x][k.y] = 1,stack[++top][0] = k.x,stack[top][1] = k.y;
        rep(i,1,4)
        {
            int kx = k.x + sx[i],ky = k.y + sy[i];
            if(vis[kx][ky]) continue;
            //if(kx < 1 || ky < 1) continue;
            if(g[kx][ky] == -1)
            {
                while(top) vis[stack[top][0]][stack[top][1]] = 0,top--;
                return 0;
            }
            else if(g[kx][ky] == f) q.push((node){kx,ky});
        }
    }
    return 1;
}

bool pduse(int x,int y)
{
    return g[x][y] != -1;
}

bool pdeat(int x,int y,bool f)
{
    bool fla = 0;
    g[x][y] = f;
    rep(i,1,4)
    {
        int kx = x + sx[i],ky = y + sy[i];
        if(kx < 1 || ky < 1) continue;
        if(g[kx][ky] == (f^1))
        {
//            printf("!%d %d\n",kx,ky);
            if(pddie(kx,ky,f^1))
            {
//                printf("@\n");
                while(top)
                {
                    vis[stack[top][0]][stack[top][1]] = 0;
                    g[stack[top][0]][stack[top][1]] = -1,top--;
                }
                fla = 1;
            }
        }
    }
    g[x][y] = -1;
    return fla;
}

int dfs(int x,int y,int dir,bool f)
{
    if(g[x][y] != f) return 0;
    else if(x < 1 || y < 1) return 0;
    else return dfs(x + dx[dir],y + dy[dir],dir,f) + 1;
}

bool pdwin(int x,int y,bool f)
{
    if(dfs(x,y,1,f) + dfs(x,y,5,f) - 1 >= p) return 1;
    if(dfs(x,y,2,f) + dfs(x,y,6,f) - 1 >= p) return 1;
    if(dfs(x,y,3,f) + dfs(x,y,7,f) - 1 >= p) return 1;
    if(dfs(x,y,4,f) + dfs(x,y,8,f) - 1 >= p) return 1;
    return 0;
}

void printgraph()
{
    rep(l,1,10)
    {
        rep(j,1,10)
        {
            if(g[l][j] == 1) putchar('O');
            else if(g[l][j] == 0) putchar('X');
            else putchar('.');
        }
        enter;
    }
}

int main()
{
    freopen("fir.in","r",stdin);
    freopen("fir.out","w",stdout);
    memset(g,-1,sizeof(g));
    n = read(),p = read();
    rep(i,1,n)
    {
        x = read(),y = read();
        if(pduse(x,y)) printf("illegal\n"),exit(0);
        else if(pdeat(x,y,i&1))
        {
            g[x][y] = i&1;
            if(pdwin(x,y,i&1))
            {
                (i&1) ? printf("ITer %d\n",i) : printf("Kitty %d\n",i);
                return 0;
            }
        }
        else if(pddie(x,y,i&1)) printf("illegal\n"),exit(0);
        g[x][y] = i&1;
        if(pdwin(x,y,i&1))
        {
            (i&1) ? printf("ITer %d\n",i) : printf("Kitty %d\n",i);
            return 0;
        }
//        printgraph();
    }
    printf("draw\n");
    return 0;
}
View Code

std:

#include<bits/stdc++.h>
using namespace std;
int f[1111][1111],n,x,y,curx,cury,X,cnt;
bool used[1111][1111],fl,cur;
int dx[]= {1,0,-1,0},dy[]= {0,1,0,-1};
int dxx[]= {1,-1,0,0,1,-1,1,-1},dyy[]= {0,0,1,-1,-1,1,1,-1};
vector<pair<int,int> > v;
void dfs(int x,int y,int ff)
{
    used[x][y]=1;
    v.push_back(make_pair(x,y));
    for (int j=0; j<4; j++)
    {
        if (fl) return;
        int xx=x+dx[j],yy=y+dy[j];
        if (used[xx][yy]) continue;
        if (!f[xx][yy])
        {
            fl=1;
            return;
        }
        if (f[xx][yy]==ff) dfs(xx,yy,ff);
    }
}
bool DFS(int x,int y)
{
    v.clear();
    fl=0;
    dfs(x,y,f[x][y]);
    if (!fl)
    {
        for (int i=0; i<v.size(); i++)
        {
            f[v[i].first][v[i].second]=0;
        }
    }
    for (int i=0; i<v.size(); i++)
    {
        used[v[i].first][v[i].second]=0;
    }
    return fl;
}
int main()
{
    freopen("FIR.in","r",stdin);
    freopen("FIR.out","w",stdout);
    scanf("%d%d",&n,&X);
    for (int i=1; i<=n; i++)
    {
        scanf("%d%d",&x,&y);
        if (f[x][y])
        {
            printf("illegal\n");
            return 0;
        }
        f[x][y]=(i&1)+1;
        if (f[x][y+1] && f[x][y+1]!=f[x][y]) DFS(x,y+1);
        if (f[x+1][y] && f[x+1][y]!=f[x][y]) DFS(x+1,y);
        if (f[x][y-1] && f[x][y-1]!=f[x][y]) DFS(x,y-1);
        if (f[x-1][y] && f[x-1][y]!=f[x][y]) DFS(x-1,y);
        if (!DFS(x,y))
        {
            printf("illegal\n");
            return 0;
        }
        for (int j=0; j<4; j++)
        {
            curx=x;
            cury=y;
            cnt=1;
            for (int k=0; k<X; k++)
            {
                curx+=dxx[j*2];
                cury+=dyy[j*2];
                if (f[curx][cury]!=f[x][y]) break;
                cnt++;
            }
            curx=x;
            cury=y;
            for (int k=0; k<X; k++)
            {
                curx+=dxx[j*2+1];
                cury+=dyy[j*2+1];
                if (f[curx][cury]!=f[x][y]) break;
                cnt++;
            }
            if (cnt>=X)
            {
                if (i&1) printf("ITer %d\n",i);
                else printf("Kitty %d\n",i);
                return 0;
            }
        }
    }
    printf("draw\n");
    return 0;
}
View Code

T2.maze

期望得分30,实际得分30

这道题考试的时候先写了30分暴力bfs,之后想到50分可以DP,但是死活没调出来……

然后考完发现自己忘记从0枚举,然后还忘记判断不能走的格子的情况了……

正解很简洁,我们必然要经过大对角线上的一点,从(1,1)走到大对角线上的一点最多有220种情况,同理(n,m)也一样。所以我们可以先处理(1,1)到大对角线上点的所以情况,之后从(n,m)出发汇合。至于如何存储数值,我们只需要用强无敌的map映射即可。

看一下代码。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<utility>
#include<map>
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
using namespace std;
typedef long long ll;
const int M = 100005;
const int N = 10000005;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
    if(ch == '-') op = -1;
    ch = getchar();
    }
    while(ch >='0' && ch <= '9')
    {
    ans *= 10;
    ans += ch - '0';
    ch = getchar();
    }
    return ans * op;
}

int n,m,kx,a[25][25],cnt,maxn,dx[3] = {0,0,1},dy[3] = {0,1,0},dp[25][25][40005];
ll ans;
map <int,ll> pm[25];

void dfs(int x,int y,int sum)
{
    if(!a[x][y]) return;
    if(x + y == n + 1)
    {
    pm[x][sum]++;
    return;
    }
    if(x < n) dfs(x+1,y,sum^a[x+1][y]);
    if(y < m) dfs(x,y+1,sum^a[x][y+1]);
}

void getans(int x,int y,int sum)
{
    if(!a[x][y]) return;
    if(x + y == n + 1)
    {
    ans += pm[x][kx^sum^a[x][y]];
    return;
    }
    if(x > 1) getans(x-1,y,sum^a[x-1][y]);
    if(y > 1) getans(x,y-1,sum^a[x][y-1]);
}

int main()
{
    n = read(),m = read(),kx = read();
    rep(i,1,n) 
    rep(j,1,m) a[i][j] = read(),maxn = max(maxn,a[i][j]);
    if(maxn <= 10000)
    {
    dp[1][1][a[1][1]] = 1;
    rep(i,1,n)
    {
        rep(j,1,m)
        {
        if(a[i+1][j]) rep(k,0,40000) dp[i+1][j][k^a[i+1][j]] += dp[i][j][k];
        if(a[i][j+1]) rep(k,0,40000) dp[i][j+1][k^a[i][j+1]] += dp[i][j][k];
        }
    }
    printf("%d\n",dp[n][m][kx]);
    }
    else dfs(1,1,a[1][1]),getans(n,m,a[n][m]),printf("%lld\n",ans);
    return 0;
}
View Code

T3.snowman

期望得分30,实际得分30.

这个题我没有什么思路,但是要求最小值最大想到二分答案,之后好像只会暴力判断了。这个复杂度其实我不会求……因为每次判断的时间非常不稳定。不过自己随机了几组5000的数据都能过,没什么问题。

之后正解需要差分转化,但是后面涉及到SA我就不会了orz,把题解copy一下吧(听Dukelv说可以hash过?)

考虑两个串和谐的条件:a 1 -b 1 =...=a n -b n ,可以把它改为a 1 -a 2 =b 1 -b 2 ,a 2 -a 3 =b 2 -b 3 ...a n-1 -a n =b n-1 -b n 。所以我们可以把原串差分,然后就可以把它转成字符串匹配的问题。
考虑 Subtask 2,将差分后的串哈希,枚举两个串的起点,二分地求出它们最多能匹配几个雪人。复杂度 O(N 2 logN)
考虑 Subtask 3,求出差分过后的串的 sa 和 lcp,考虑二分答案,记当前二分的答案为 x。在 check 时,我们枚举一个 l,求出最大的 r 使得 min(lcp[l],lcp[l+1]...lcp[r])≥x,然后判断max(sa[l]...sa[r+1])-sa[l]是否≥x 即可,这可以用 set 和权值线段树实现。复杂度 O(Nlog 2 N)
考虑 Subtask 4,考虑 O(NlogN)地求出 sa,还是二分答案,其实在 check 的时候我们只需要考虑每一个 lcp[l]≥x...lcp[r]≥x 的串里 max(sa[l],...,sa[r+1])- min(sa[l],...,sa[r+1])是否
≥x 即可。复杂度 O(NlogN)。
当然,这个题也可以用 SAM 做,对于 SAM 上的每一个点,求 出 它 right 集 合 里 的 最 大 值 mx 和 最 小 值 mn , 用min(len+1,mx-mn)更新答案即可。

暴力代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<utility>
#include<map>
#include<ctime>
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
using namespace std;
typedef long long ll;
const int M = 500005;
const int N = 10000005;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >='0' && ch <= '9')
    {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
    }
    return ans * op;
}

int n,x,a[M],l,r,ans;

bool pd(int p,int q,int x)
{
    int k = a[p] - a[q];
    rep(i,1,x-1) if((a[p+i] - a[q+i]) != k) return 0;
//    printf("%d %d\n",p,q);
    return 1;
}

bool check(int x)
{
    if(x > (n >> 1)) return 0;
    rep(i,1,n-(x<<1)+1)
    {
        rep(j,i+x,n-x+1) if(pd(i,j,x)) return 1;
    }
    return 0;
}

int main()
{
    freopen("snowman.in","r",stdin);
    freopen("snowman.out","w",stdout);    
    srand(time(NULL));
    n = read();
    rep(i,1,n) a[i] = read();
    if(n <= 5000)
    {
        l = 1,r = n;
        while(l < r)
        {
            int mid = (l+r) >> 1;
            if(check(mid)) ans = mid,l = mid+1;
            else r = mid;
        }
        printf("%d\n",ans);
    }
    else printf("%d\n",rand()%n);
    return 0;
}
/*
10 
1 2 3 4 5 6 7 8 9 10
*/
View Code

std:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int s[1111111];
int n,rank[1111111],sa[1111111],k,fst[1111111],sec[1111111],h,lcp[1111111],x[1111111],l,r,mid;
int cmp(int i,int j,int l)
{
    if(i+l*2>n+1 || j+l*2>n+1) return 1;
    return sec[i]!=sec[j] || sec[i + l]!=sec[j + l];
}
void make_sa()
{
    for (int i=1; i<=n; i++) x[i]=s[i];
    sort(x+1,x+1+n);
    int m=unique(x+1,x+1+n)-x-1;
    for (int i=1; i<=n; i++)
        s[i]=lower_bound(x+1,x+1+m,s[i])-x;
    memset(x, 0, sizeof(x));
    for (int i=1; i<=n; i++) ++x[fst[i]=s[i]];
    for (int i=1; i<=m; i++) x[i]+=x[i - 1];
    for (int i=n; i>0; i--) sa[x[s[i]]--]=i;
    for (int i=1; i<n; i<<=1)
    {
        int p=0;
        for (int j=n-i+1; j<=n; j++) sec[++p] = j;
        for (int j=1; j<=n; j++) if(sa[j]>i) sec[++p]=sa[j] - i;
        memset(x,0,sizeof(x));
        for (int j=1; j<=n; j++) ++x[fst[sec[j]]];
        for (int j=1; j<=m; j++) x[j]+=x[j - 1];
        for (int j=n; j>0; j--) sa[x[fst[sec[j]]]--]=sec[j];
        memcpy(sec,fst,sizeof(sec));
        fst[sa[1]]=m=1;
        for (int j=2; j<=n; j++) fst[sa[j]]=(m+=cmp(sa[j - 1],sa[j],i));
    }
}
void make_lcp()
{
    int h=0;
    for (int i=1; i<=n; i++) rank[sa[i]]=i;
    for (int i=1; i<=n; i++)
    {
        int j=sa[rank[i]-1];
        if (h>0) h--;
        for (; i+h<=n && j+h<=n; h++)
        {
            if (s[i+h]!=s[j+h]) break;
        }
        lcp[rank[i]-1]=h;
    }
}
bool check(int x)
{
    int pos=1,mn=1e9,mx=0;
    while(pos<n && lcp[pos]<x-1) pos++;
    while(pos<n)
    {
        mn=sa[pos];
        mx=sa[pos];
        while(pos<n && lcp[pos]>=x-1)
        {
            pos++;
            mn=min(mn,sa[pos]);
            mx=max(mx,sa[pos]);
        }
        while(pos<n && lcp[pos]<x-1) pos++;
        if (mx-mn>=x) return 1;
    }
    return 0;
}
int rpos, mmx;
char str[10000000];
char readc()
{
    if(!rpos) mmx = fread(str, 1, 10000000, stdin);
    return rpos == mmx ? 0 : str[rpos++];
}
int read()
{
    int x;
    char c;
    while((c=readc())<'0' || c>'9');
    x=c-'0';
    while((c=readc())>='0' && c<='9') x=x*10+c-'0';
    return x;
}
int main()
{
    freopen("snowman.in","r",stdin);
    freopen("snowman.out","w",stdout);
    n=read();
    for (int i=1; i<=n; i++) x[i]=read();
    for (int i=1; i<n; i++)
    {
        s[i]=x[i+1]-x[i];
    }
    n--;
    make_sa();
    make_lcp();
    /*for(int i = 1; i <= n; i++) printf("%d ", s[i]);
    putchar('\n');
    for(int i = 1; i <= n; i++) printf("%d ", sa[i]);
    putchar('\n');
    for(int i = 1; i <= n; i++) printf("%d ", lcp[i]);
    putchar('\n');*/
    l=0;
    r=n;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if (check(mid)) l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",r);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/captain1/p/9789483.html