8.23 Test——NOIP模拟题#2

T1:Nim

Nim 游戏·改(nim.c/cpp/pas)

 

1.1  题目描述

 众所周知的 Nim 游戏是这样的:有 n 堆石子,小 A 和小 B 轮流取石子,小 A 先操作,每次选择一堆石子,在这堆中取走任意多个石子,最后没有石子可取的人输。现在为了加强 Nim 游戏难度,每堆非空石子有一次额外的特殊机会,即耗掉这个机会,然后什么也不拿走,而其他条件都不变。当然,如果你将一堆本来有额外机会的石子拿空,那么这次额外机会也就没有了。 现在假设小 A 和小 B 都绝顶聪明,他们将进行 T 轮游戏。每轮游戏若小 A 必胜,输出“A”,否则输出“B”。

1.2  输入格式

 第一行为一个整数 T,表示游戏轮数。  接下来 T 组数据。每组数据第一行包含一个数 n,表示石子堆数;接下来一行 n 个数,表示每堆石子的个数 A[i]。

1.3  输出格式

对于每轮游戏输出一行,表示必胜的玩家。

 

1.4  样例输入

2

2

1  2

2

2  2

1.5  样例输出

A

B

1.6  数据范围与约定

对于前 20%的数据 T=3 , n=3 , A[i]<=4。

对于前 40%的数据 T<=100000 , n=3 , A[i]<=40

对于 100%的数据 n<=100000,n*T<=1000000 , 1<=A[i]<=1000000000。

 

解析:

  考场爆0,好像可以 打表找规律,不会证明,博弈论是真的菜

 代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

int T, n, ans;

int main()
{
    freopen("nim.in", "r", stdin);
    freopen("nim.out", "w", stdout);
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        ans = 0;
        for(int i = 1; i <= n; ++i)
        {
            int x;
            scanf("%d", &x);

            ans ^= (x&1? x + 1: x - 1);
        }
        printf("%s\n", ans? "A": "B");
    }
    return 0;
}
nim

T2:Party

聚会(party.c/cpp/pas)

2.1  题目描述

 你要精心策划一场聚会。  现在有 n 个人,一共有 m 个认识关系,认识的人一定是相互认识的。由于这次聚会十分重要,你希望被邀请的每个人都直接或间接认识,不仅如此,为了避免尴尬,你还希望每个被邀请的人都直接认识另外至少 d 个被邀请的人。作为策划者,你希望使得被邀请的人最多。注意同一对关系最多只会出现一次,且不会出现自环。  你需要输出被邀请的人数,并且将被邀请的人的编号从小到大输出。为了避免你的重度选择恐惧症发作,当存在多个答案时,你需要使得被邀请的人的编号越小越好。

 

2.2  输入格式

    第一行为三个整数 n,m,d,分别表示人数、认识关系数以及题中给出的限制 d。      接下来 m 行 ,每行两个数 a 和 b,表示 a、b 相互认识。 

2.3  输出格式

第一行一个整数,表示被邀请的人数 k。保证有解,即 k>0。        第二行 k 个整数,从小到大输出你邀请的人的编号。

2.4  样例输入

4 4 2

1  2

2  3

3  4

4  2

 2.5  样例输出

3

2 3 4

 

2.6  数据范围与约定    

对于 20%的数据,n<=18,m<=50

对于 100%的数据,2<=n<=200000, 1<=m<=200000 , 1<=d<n 

解析:

  挺简单的,考场AC, 就是不断把度数小于$d$的点删去, 建新图,重新统计度数,再接着删点,直到每个点的度数都大于等于$d$,删完后会形成多个连通块,分别统计答案

 代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 200004;

inline int read()
{
    int ret, f=1;
    char c;
    while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')f=-1;
    ret=c-'0';
    while((c=getchar())&&(c>='0'&&c<='9'))ret=(ret<<3)+(ret<<1)+c-'0';
    return ret*f;
}

int n, m, d, ans, ind[maxn], stak[maxn], top, a[maxn];
bool col[maxn], vis[maxn];

int head[2][maxn], tot[2];
struct edge{
    int nxt, to;
}e[2][maxn<<1];

void Addedge(int x, int y, int opt)
{
    e[opt][++tot[opt]] = (edge){head[opt][x], y};
    head[opt][x] = tot[opt]; 
}

void dfs(int x, int now)
{
    vis[x] = 1;
    stak[++top] = x;
    for(int i = head[now][x]; i; i = e[now][i].nxt)
    {
        int id = e[now][i].to;
        if(col[id] && !vis[id])
            dfs(id, now);
    }
}

void work()
{
    int now = 0;
    bool fl = 1;
    while(fl)
    {
        tot[now^1] = 0;
        fl = 0;
        for(int i = 1; i <= n; ++i)
            if(col[i])
            {
                head[now^1][i] = 0;
                ind[i] = 0;
                for(int j = head[now][i]; j; j = e[now][j].nxt)
                    if(col[e[now][j].to])
                    {
                        Addedge(i, e[now][j].to, now^1);
                        ind[i] ++;
                    }
                if(ind[i] < d)
                {
                    col[i] = 0;
                    fl = 1;
                }
            }
        now ^= 1;
    }
    for(int i = 1; i <= n; ++i)
        if(col[i] && !vis[i])
        {
            top = 0;
            dfs(i, now);
            if(top > ans)
            {
                for(int j = 1; j <= top; ++j)
                    a[j] = stak[j];
                sort(a + 1, a + top + 1);
                ans = top;
            }
            else if(top == ans)
            {
                sort(stak + 1, stak + top + 1);
                if(a[1] > stak[1])
                {
                    for(int j = 1; j <= top; ++j)
                        a[j] = stak[j];
                }
            }
        }
}

int main()
{
    freopen("party.in", "r", stdin);
    freopen("party.out", "w", stdout);
    n = read();m = read();d = read();
    for(int i = 1; i <= m; ++i)
    {
        int u = read(), v = read();
        Addedge(u, v, 0);
        Addedge(v, u, 0);
        ind[u] ++;
        ind[v] ++;
    }
    for(int i = 1; i <= n; ++i)
        if(ind[i] >= d)
            col[i] = 1;
    work();
    printf("%d\n", ans);
    for(int i = 1; i <= ans; ++i)
        printf("%d ", a[i]);
    return 0;
}
party

T3:History

历史(history.c/cpp/pas) 

 

3.1  题目描述

历史学家小A正在研究一个奇怪的王国的历史。当前阶段的任务是研究该国的交通。 根据这个奇怪的王国的史书记载,史书开始记载前这个王国有 n 个城市(城市从 0 开始标号),但所有城市之间都没有道路相连。 每一年,在位的国王会修建一条 x 到 y 的双向道路,一条道路可能被修建多次,但不会修建起点和终点为同一个城市的道路。 而在这之间,国王会计划进行若干次旅行。对于计划进行的一次旅行 st->ed,如果当时能完成这次旅行,而 t 年前不能完成这次旅行,那么国王会对之前的建设成果感到满意,否则他会很生气,并在下一次计划旅行前都让史官记录下错误的修建道路的信息,即把 x、y 记作(x+n-c) mod n,(y+n-c) mod n。

当然在这些年中也发生了若干次国王的交替,初始国王的 c 值为 0,而每个国王的 c 值不一定相同,但在国王在位期间 c 值不会改变,新上位的国王开始处于不生气的状态。 请根据史书帮助小 A 得出国王每次对于计划旅行是否满意,从而辅助小 A 能够研究该国的交通信息。

3.2  输入格式

第一行为两个整数 n,m,表示初始城市数和历史书记载的内容数。     接下来 m 行,每行是以下三种格式之一:

1  . K v :表示国王交替,新国王的 c 值为 v

2  . R x y:表示史书上记载的是国王修建了 x 到 y 的双向道路,但注意这个记录的可能不是实际状况。

3  . T st ed t:表示国王计划进行的一次 st->ed 的旅行,且比较的是 t 年前的情况(国王可能会和史书开始记载以前的情况比较),注意这个记录的肯定是实际情况。

注意只有遇到 R 操作才会使年份的计数+1。  

3.3  输出格式

 输对于每个 T 的记录输出一行,如果此次计划旅行令国王满意,则输出 Y,否则输出 X。

3.4  样例输入

3 7

R 0 1

T 0 1 1

K 1

R 0 1

T 0 1 1

R 0 1

T 0 2 1

3.5  样例输出

Y

N

Y

3  .6  数据范围与约定

对于 30%的数据,保证 n<=1000 ,m<=3000。

另 30%的数据满足没有发生国王的交替。

对于 100%的数据,保证 n,m<=300000,0<=v,x,y,st,ed<n,0<=t<m。数据有梯度

解析:

   考场一眼可持久化并查集,唔...然而不会, 然后发现询问可离线,于是就变成了离线操作了,把需要查询的时间相同的询问存在一起,每个询问有两个需要查询的时间,枚举时间,先更新并查集,再处理当前时间的询问

  国王的生气不好处理,我们发现每次修路都与之前最后一次国王旅行是否满意有关, 因此需要每年结束时都需要记录最后一次旅行的国王状态

  然后是一个我写挂了的细节,如果国王在最后一次旅行后上位, $c$值清0, 如果在某年中间,但在最后一次旅行前上位,最后一次旅行后若不满意则需要用新的国王的$c$。我就是这里没有判断,最后只有50分

 代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 300004, inf = (1<<30);

inline int read()
{
    int ret, f=1;
    char c;
    while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')f=-1;
    ret=c-'0';
    while((c=getchar())&&(c>='0'&&c<='9'))ret=(ret<<3)+(ret<<1)+c-'0';
    return ret*f;
}

int n, m, f[maxn], yer, cnt, ans[maxn];
int cit[2][maxn], kin[maxn], c, now;
bool vis[maxn];

int head[2][maxn], tot[2];
struct ques{
    int nxt, u, v, num;
}q[2][maxn<<1];

void Addques(int x, int u, int v, int opt, int num)
{
    q[opt][++tot[opt]] = (ques){head[opt][x], u, v, num};
    head[opt][x] = tot[opt];
}

int Find(int x)
{
    return f[x] == x? x: f[x] = Find(f[x]);
}

int main()
{
    freopen("history.in", "r", stdin);
    freopen("history.out", "w", stdout);
    n = read();m = read();
    for(int i = 0; i <= m; ++i)
        kin[i] = inf;
    for(int i = 1; i <= m; ++i)
    {
        char opt[3];
        scanf("%s", opt);
        if(opt[0] == 'K')
        {
            int x = read();
            kin[yer] = x;
            vis[yer] = 1;
        }
        else if(opt[0] == 'R')
        {
            cit[0][++yer] = read();
            cit[1][yer] = read();
        }
        else
        {
            int x = read() + 1, y = read() + 1, t = read();
            Addques(max(yer - t, 0), x, y, 0, ++cnt);
            Addques(yer, x, y, 1, cnt);
            vis[yer] = 0;
        }
    }
    for(int i = 1; i <= n; ++i)
        f[i] = i;
    for(int i = 0; i <= yer; ++i)
    {
        int fu = Find(((cit[0][i] + c) % n) + 1), fv = Find(((cit[1][i] + c) % n) + 1);
        if(i && fu != fv)
            f[fv] = fu;
        for(int j = head[0][i]; j; j = q[0][j].nxt)
        {
            fu = Find(q[0][j].u);
            fv = Find(q[0][j].v);
            ans[q[0][j].num] = (fu == fv) - ans[q[0][j].num];
        }
        for(int j = head[1][i]; j; j = q[1][j].nxt)
        {
            fu = Find(q[1][j].u);
            fv = Find(q[1][j].v);
            ans[q[1][j].num] = (fu == fv) - ans[q[1][j].num];
            if(j == head[1][i] && !ans[q[1][j].num])
                c = now;
            else if(j == head[1][i])
                c = 0;
        }
        if(kin[i] != inf)
        {
            if(c == now && !vis[i])
                c = kin[i];
            else
                c = 0;
            now = kin[i];
        }
    }
    for(int i = 1; i <= cnt; ++i)
        printf("%s\n", ans[i]? "Y": "N");
    return 0;
}
history

猜你喜欢

转载自www.cnblogs.com/Joker-Yza/p/11402775.html