首页 > 其他分享 >【考后总结】NOI 统一省选 2023

【考后总结】NOI 统一省选 2023

时间:2023-04-14 22:24:53浏览次数:42  
标签:考后 rnow2 省选 tot int rnow1 continue bnow NOI

文化课补完了,但是考试考炸了,所以来补题。

D1T1 火车站 station

实际上只需要判断从 \(x\) 能否一直向一个方向移动且每个位置能不能作为这个方向的终点站。

区间覆盖差分一下即可。

点击查看代码
int n,m,x;
int st[maxn][2],cov[maxn];
bool vis[maxn];

int main(){
    freopen("station.in","r",stdin);
    freopen("station.out","w",stdout);
    n=read(),m=read(),x=read();
    for(int i=1;i<=m;++i){
        int l=read(),r=read();
        st[l][0]=1,st[r][1]=1;
        ++cov[l],--cov[r];
    }
    for(int i=1;i<n;++i) cov[i]+=cov[i-1];
    for(int i=x-1;i>=1;--i){
        if(!cov[i]) break;
        if(st[i][0]) vis[i]=1;
    }
    for(int i=x+1;i<=n;++i){
        if(!cov[i-1]) break;
        if(st[i][1]) vis[i]=1;
    }
    for(int i=1;i<=n;++i){
        if(vis[i]) printf("%d ",i);
    }
    printf("\n");
    return 0;
}

D2T1 过河卒 zu

不是博弈论,是博弈论暴搜。

图很小,可以压成 \(10^6\) 的状态记录三个棋子的位置,合法转移直接连边。

不好解决的问题是可能出现平局——成环,这样不能从起始状态开始搜。改成从每个结束状态开始搜,由于根据步数的奇偶性可以判断出当前是谁的回合,我们只需要拓扑转移即可。

如果一个状态当前被转移到的都是必败状态,那么一直取步数的 \(\max\),一旦出现必胜决策可以直接入队,由于 BFS,此时步数一定最小,且在当前位置决策者一定会选这种必胜决策。也就是魔改了一下拓扑排序。

在答案处要注意的是,如果是必败状态且初始状态处于一个环中,那么会选择走环来达到不败的情况,要特判一下。(在转移过程中由于没有被完全剥出的节点不会入队,实际上也是存在不败一定选不败)

点击查看代码
int t,n,m;
char s[15][15];
pii B,R1,R2;
struct state{
    pii bp,rp1,rp2;
    //0->B 1->R
    state()=default;
    state(pii bp_,pii rp1_,pii rp2_):bp(bp_),rp1(rp1_),rp2(rp2_){}
}S[maxn];
bool opt[maxn];
int winchk[maxn];
int mp[11][11][11][11][11][11];
int tot,mark;
int dx[4]={-1,0,0,1},dy[4]={0,-1,1,0};

struct edge{
    int to,nxt;
}e[maxn<<3];
int head[maxn],cnt;
int deg[maxn];
inline void add_edge(int u,int v){
    e[++cnt].to=v,e[cnt].nxt=head[u],head[u]=cnt;
    ++deg[v];
}

queue<int> q;
int dp[maxn];

int main(){
    freopen("zu.in","r",stdin);
    freopen("zu.out","w",stdout);
    read(),t=read();
    while(t--){
        n=read(),m=read();
        for(int i=1;i<=n;++i) scanf("%s",s[i]+1);
        B=R1=R2=make_pair(0,0);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                if(s[i][j]=='X') B=make_pair(i,j);
                if(s[i][j]=='O'){
                    if(!R1.x) R1=make_pair(i,j);
                    else R2=make_pair(i,j);
                }
            }
        }
        tot=0;
        memset(mp,0,sizeof(mp));
        for(int bx=1;bx<=n;++bx){
            for(int by=1;by<=m;++by){
                for(int rx1=1;rx1<=n;++rx1){
                    for(int ry1=1;ry1<=m;++ry1){
                        for(int rx2=1;rx2<=n;++rx2){
                            for(int ry2=1;ry2<=m;++ry2){
                                pii bnow=make_pair(bx,by),rnow1=make_pair(rx1,ry1),rnow2=make_pair(rx2,ry2);
                                if(bx>B.x) continue;
                                if(s[bnow.x][bnow.y]=='#'||s[rnow1.x][rnow1.y]=='#'||s[rnow2.x][rnow2.y]=='#') continue;
                                if(rnow1==rnow2) continue;
                                int sumstep=abs(B.x-bx)+abs(B.y-by)+abs(R1.x-rx1)+abs(R1.y-ry1)+abs(R2.x-rx2)+abs(R2.y-ry2);
                                S[++tot]=state(bnow,rnow1,rnow2),opt[tot]=sumstep&1^1,winchk[tot]=-1;
                                if(bnow.x==1) winchk[tot]=0;
                                else if(bnow==rnow1||bnow==rnow2) winchk[tot]=opt[tot]^1;
                                else{
                                    if(!opt[tot]){
                                        bool chk=1;
                                        for(int i=0;i<3;++i){
                                            int xx=bnow.x+dx[i],yy=bnow.y+dy[i];
                                            if(xx<1||xx>n||yy<1||yy>m) continue;
                                            if(s[xx][yy]!='#') chk=0;
                                        }
                                        if(chk) winchk[tot]=1;
                                    }
                                    else{
                                        bool chk=1;
                                        for(int i=0;i<4;++i){
                                            int xx=rnow1.x+dx[i],yy=rnow1.y+dy[i];
                                            if(xx<1||xx>n||yy<1||yy>m) continue;
                                            if(s[xx][yy]!='#'&&make_pair(xx,yy)!=rnow2) chk=0;
                                        }
                                        for(int i=0;i<4;++i){
                                            int xx=rnow2.x+dx[i],yy=rnow2.y+dy[i];
                                            if(xx<1||xx>n||yy<1||yy>m) continue;
                                            if(s[xx][yy]!='#'&&make_pair(xx,yy)!=rnow1) chk=0;
                                        }
                                        if(chk) winchk[tot]=0;
                                    }
                                }
                                mp[bx][by][rx1][ry1][rx2][ry2]=tot;
                                // printf("%d (%d %d) (%d %d) (%d %d)\n",tot,S[tot].bp.x,S[tot].bp.y,S[tot].rp1.x,S[tot].rp1.y,S[tot].rp2.x,S[tot].rp2.y);
                                if(bnow==B&&rnow1==R1&&rnow2==R2) mark=tot;
                            }
                        }
                    }
                }
            }
        }
        // printf("%d\n",mark);
        for(int i=1;i<=tot;++i) head[i]=0,deg[i]=0;
        cnt=0;
        for(int i=1;i<=tot;++i){
            if(winchk[i]!=-1) q.push(i);
            pii bnow=S[i].bp,rnow1=S[i].rp1,rnow2=S[i].rp2;
            if(!opt[i]){
                //move R
                for(int j=0;j<4;++j){
                    int xx=rnow1.x+dx[j],yy=rnow1.y+dy[j];
                    if(xx<1||xx>n||yy<1||yy>m) continue;
                    if(mp[bnow.x][bnow.y][xx][yy][rnow2.x][rnow2.y]){
                        int nxt=mp[bnow.x][bnow.y][xx][yy][rnow2.x][rnow2.y];
                        if(winchk[nxt]!=-1) continue;
                        add_edge(i,nxt);
                    }
                }
                for(int j=0;j<4;++j){
                    int xx=rnow2.x+dx[j],yy=rnow2.y+dy[j];
                    if(xx<1||xx>n||yy<1||yy>m) continue;
                    if(mp[bnow.x][bnow.y][rnow1.x][rnow1.y][xx][yy]){
                        int nxt=mp[bnow.x][bnow.y][rnow1.x][rnow1.y][xx][yy];
                        if(winchk[nxt]!=-1) continue;
                        add_edge(i,nxt);
                    }
                }
            }
            else{
                //move B
                for(int j=1;j<4;++j){
                    int xx=bnow.x+dx[j],yy=bnow.y+dy[j];
                    if(xx<1||xx>n||yy<1||yy>m) continue;
                    if(mp[xx][yy][rnow1.x][rnow1.y][rnow2.x][rnow2.y]){
                        int nxt=mp[xx][yy][rnow1.x][rnow1.y][rnow2.x][rnow2.y];
                        if(winchk[nxt]!=-1) continue;
                        add_edge(i,nxt);
                    }
                }
            }
        }
        for(int i=1;i<=tot;++i) dp[i]=0;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            // printf("%d (%d %d) (%d %d) (%d %d) opt:%d winchk:%d dp:%d\n",u,S[u].bp.x,S[u].bp.y,S[u].rp1.x,S[u].rp1.y,S[u].rp2.x,S[u].rp2.y,opt[u],winchk[u],dp[u]);
            for(int i=head[u];i;i=e[i].nxt){
                int v=e[i].to;
                if(winchk[u]==opt[u]){
                    //必败策略
                    if(winchk[v]==opt[v]) continue;
                    winchk[v]=opt[v]^1,dp[v]=max(dp[v],dp[u]+1);
                    --deg[v];
                    if(!deg[v]) q.push(v);
                }
                else{
                    //必胜策略
                    if(winchk[v]==opt[v]) continue;
                    winchk[v]=opt[v],dp[v]=dp[u]+1;
                    deg[v]=0;
                    q.push(v);
                }
            }
        }
        if(winchk[mark]==-1) printf("Tie\n");
        else if(winchk[mark]==opt[mark]) printf("Red %d\n",dp[mark]);
        else if(!deg[mark]) printf("Black %d\n",dp[mark]);
        else printf("Tie\n");
    }
    return 0;
}

没有做出的问题在于如何处理平局以及压成状态建图搜索的简单转换。

标签:考后,rnow2,省选,tot,int,rnow1,continue,bnow,NOI
From: https://www.cnblogs.com/SoyTony/p/Problems_in_NOI_Unified_Provincial_Selection_2023.html

相关文章

  • 联合省选2023
    火车站小丑题。直接从起点开始往左往右扫即可。submission城市建造不开longlong间祖宗。首先你手完一下可以发现一个点双上面要么不选,要么选一个,要么全选,并且一定是在圆方树上选一个联通块。这样你就可以\(O(n^2)\)的dp了。就是说你可以枚举最小联通块的大小\(p\),然......
  • [Ynoi2018] 天降之物
    [Ynoi2018]天降之物这个根号分治太神啦。首先考虑一个朴素的暴力:对每个数维护出现位置的std::vector这样查询可以两个指针遍历std::vector做到平方复杂度。注意到复杂度和出现次数有关,那么就可以考虑阈值分治了,然而合并的操作使得我们不好维护信息。先考虑不带修的情况,对......
  • [联合省选2023] 起航
    2023.1—2023.3报了正睿,希望省选前能再提升一下自己的水平。由于疫情反反复复,FZ一检拖到了2月份,所以直到二月份才开始停课生活。ZR的场况起起浮浮,但相对于1月有了不少进步。这次省选并没有太大的希望进队,只希望可以减小差距。2023.3.31试机。在烟雨蒙蒙中来到了附中,......
  • w2 P1008 [NOIP1998 普及组] 三连击
      主要思路:构造一个judge函数,判断是否1-9都出现了。由于三位数范围为123-987,但因为要求三个数字比例为1:2:3,所以在遍历时的范围是123-987/3。遍历范围内的每一个整数x,并判断2x,3x是否满足judge函数,满足则输出这三个数,否则继续遍历。代码如下:#include<iostream>usingnamespac......
  • [NOIP2011]铺地毯
    算法比赛真是属于同类比赛中最耗时间的了,有时候一个题一个小时都拿不下。不说了先看下这个题的解法#include<bits/stdc++.h>usingnamespacestd;inta[100001],b[100001],g[100001],k[100001];intn;intx,y;intcnt=-1;intmain(){cin>>n;for(inti=......
  • Hanoi - plus
    题目描述如果将课本上的汉诺塔问题稍做修改:给定N只盘子,3根柱子,但是允许每次最多移动相邻的M只盘子(当然移动盘子的数目也可以小于M),最少需要多少次? 输入格式输入数据仅有一行,包括两个数N和M(0<=M<=N<=8) 输出格式仅输出一个数,表示需要移动的最少次数 样例输入......
  • 「解题报告」P9169 [省选联考 2023] 过河卒
    挺套路的博弈论,实际上就是GameonGraph与GameonGraph,但是考场上多测没清空挂了。寄。并且不过ABC那个官方题解好像给的是\(O(m\logn)\)的做法,放这题是过不去的啦x首先显然三个棋子压状态大概是\(10^6\)级别的,多测\(T=10\),那么猜测是一个\(O(Tn^6)\)的做法。......
  • 往年 NOI 做题记录
    一个新坑,先把真题都刷一下大概就知道会考什么和难度怎么样了。2013向量内积给定一个\(n\)个\(m\)维向量,求出一组不同的向量\(p,q\)使其内积(点乘)在模\(k\)意义下为\(0\)。\(k=2,1\len\le2\times10^4,1\lem\le100\)或\(k=3,1\len\le10^5,1\lem\le30.\)......
  • NOI / 1.8编程基础之多维数组 04:错误探测
    描述给定n*n由0和1组成的矩阵,如果矩阵的每一行和每一列的1的数量都是偶数,则认为符合条件。你的任务就是检测矩阵是否符合条件,或者在仅改变一个矩阵元素的情况下能否符合条件。"改变矩阵元素"的操作定义为0变成1或者1变成0。输入输入n+1行,第1行为矩阵的大小n(0<n<100),以......
  • [省选联考 2023] 染色数组 题解
    题目描述给定一个长度为\(n\)的正整数数组\(A\),其中每个数都在\(1\)到\(m\)之间,从左到右排成一排。现在要将每个数字染成红色或者绿色,我们定义一个染色方案为优秀的染色方案,当且仅当它满足:每个数\(A_{i}\)要么被染成红色,要么被染成绿色。红色的数从左到右依次严格递......