牛客小白月赛13

牛客小白月赛13

闲的蛋疼打了一场小白,然后被爆踩。。。

J题好难啊,要学了莫反才能做,先留坑吧

先放一发官方题解

 

小A的签到题

链接:https://ac.nowcoder.com/acm/contest/549/A
来源:牛客网

题目描述

这是一道签到题,主要考验比赛时的手速。
接下来是一段很简单的代码,或许你提交它就可以AC。
#include<bits/stdc++.h>
using namespace std;
int main() {
    long long n;
    scanf("%lld",&n);
    long long f1=1,f2=1,f3;
    for(int i=3;i<=n;i++) {
        f3=f1+f2;
        f1=f2;
        f2=f3;
    }
    printf("%lld\n",f3*f3-f1*f1-f1*f3);
    return 0;
}

输入描述:

N一行一个整数N

输出描述:

一行一个整数表示结果
示例1

输入

3

输出

1

备注:

3N1e11
sol:XJB找找规律发现奇数是1,偶数是-1
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');    return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
ll n;
int main()
{
    R(n);
    if(n&1) puts("1"); else puts("-1");
    return 0;
}
View Code

 

链接:https://ac.nowcoder.com/acm/contest/549/B
来源:牛客网

小A的回文串

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小A非常喜欢回文串,当然我们都知道回文串这种情况是非常特殊的。所以小A只想知道给定的一个字符串的最大回文子串是多少,但是小A对这个结果并不是非常满意。现在小A可以对这个字符串做一些改动,他可以把这个字符串最前面的某一段连续的字符(不改变顺序)移动到原先字符串的末尾。那么请问小A通过这样的操作之后(也可以选择不移动)能够得到最大回文子串的长度是多少。

输入描述:

S一行一个字符串表示给定的字符串S

输出描述:

一行输出一个整数,表示通过这样的操作后可以得到最大回文子串的长度。
示例1

输入

复制
dcbaabc

输出

复制
7

说明

将前面的dcba移动到末尾变成abcdcba,这个字符串的最大回文子串就是它本身,长度为7

备注:

N1N5000

sol:直接枚举断点,然后移过去,在之后马拉车可以n2过掉此题,但是我忘了马拉车怎么写,然后其实根本不用马拉车,把整个字符串复制一遍,粘在末尾,找到整个字符串的最长回文串就是答案了
#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');    return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=5005;
int n;
char S[N<<1];
int main()
{
    int i,l,r,ans=0;
    scanf("%s",S+1);
    n=strlen(S+1);
    for(i=1;i<=n;i++) S[i+n]=S[i];
    for(i=1;i<=2*n;i++)
    {
        l=i; r=i;
        while(S[l]==S[r]&&l>=1&&r<=2*n&&r-l+1<=n) l--,r++;
        ans=max(ans,r-l+1-2);
        l=i,r=i+1;
        while(S[l]==S[r]&&l>=1&&r<=2*n&&r-l+1<=n) l--,r++;
        ans=max(ans,r-l+1-2);
    }
    Wl(ans);
    return 0;
}
/*
input
dcbaabc
output
7
*/
View Code

 

 

 

链接:https://ac.nowcoder.com/acm/contest/549/C
来源:牛客网

小A买彩票
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小A最近开始沉迷买彩票,并且希望能够通过买彩票发家致富。已知购买一张彩票需要3元,而彩票中奖的金额分别为1,2,3,4元,并且比较独特的是这个彩票中奖的各种金额都是等可能的。现在小A连续购买了n张彩票,他希望你能够告诉他至少能够不亏本的概率是多少。

输入描述:

NA一行一个整数N,为小A购买的彩票数量

输出描述:

a/bA11/100/1输出一个最简分数a/b,表示小A不亏本的概率。若概率为1,则输出1/1,概率为0,则输出0/1。
示例1

输入

复制
2

输出

复制
3/8

备注:

0n30

sol:dp随便搞搞,dp[i][j]表示买了i张彩票,一共得了j元钱,转移十分水

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');    return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=35;
int n;
ll dp[N][N<<2];
inline ll gcd(ll a,ll b)
{
    return (!b)?(a):(gcd(b,a%b));
}
int main()
{
    int i,j,k;
    R(n);
    dp[0][0]=1;
    for(i=0;i<n;i++)
    {
        for(j=i;j<=(i<<2);j++)
        {
            for(k=1;k<=4;k++) dp[i+1][j+k]+=dp[i][j];
        }
    }
    ll Fz=0,Fm;
    for(i=((n<<1)+n);i<=(n<<2);i++) Fz+=dp[n][i];
    Fm=1ll<<(n<<1);
    ll GG=gcd(Fz,Fm);
    write(Fz/GG); putchar('/'); Wl(Fm/GG);
    return 0;
}
/*
input
2
output
3/8
*/
View Code

 

 

 
 链接:https://ac.nowcoder.com/acm/contest/549/D?&headNav=acm
来源:牛客网

小A的位运算

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

位运算是一个非常重要的东西。而小A最近在学习位运算,小A看到了一道很简单的例题,是说从N个数里面选出N-1个数要让它们或起来的值最大,小A想知道这个答案是多少。你可以帮帮他吗?

输入描述:

NNNA1,A2...AN第一行一个整数N表示有N个数接下来一行N个数表示A1,A2...AN

输出描述:

一行输出个结果代表最大值
示例1

输入

复制
5
1 2 4 8 16

输出

复制
30

说明

选择2,4,8,16或的和是最大的,没有比这个更大的方案。

备注:

1N5e61Ailonglong

sol:此题有一个很显然的nlogn做法,每次删去一个数,求剩余数字的或和,我本以为会T,似乎可以过,我也不知道为什么nlogn能过5e6,大概是牛客评测姬太快了(滑稽)
#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0'); return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=5000005,inf=0x3f3f3f3f;
int n,a[N];
int Arr[33];
int main()
{
    int i,j,bo=0,Pos=0,ans=0;
    R(n);
    for(i=1;i<=n;i++)
    {
        R(a[i]);
        for(j=31;~j;j--) if(a[i]&(1<<j))
        {
            Arr[j]++;
        }
    }
    for(i=1;i<=n;i++)
    {
        int Sum=0;
        for(j=31;~j;j--) if(a[i]&(1<<j)) Arr[j]--;
        for(j=31;~j;j--) if(Arr[j]) Sum+=(1<<j);
        ans=max(ans,Sum);
        for(j=31;~j;j--) if(a[i]&(1<<j)) Arr[j]++;
    }
    Wl(ans);
    return 0;
}
/*
input
5
1 2 4 8 16
output
30
*/
View Code

 

 

链接:https://ac.nowcoder.com/acm/contest/549/E
来源:牛客网

小A的路径

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小A来到了一个陌生的城镇,这个城镇与其它城镇之间构成了集群。城镇之间的路径都是单向的,而小A每一天都能由一个城镇走到另外一个城镇。小A将会连续走k天,直到抵达某个城镇。也许他并不能走到这个城镇,那么可以认为不存在这样的路径,也就是路径数为0。否则就会有若干条路径可以抵达某个城镇。现在他想知道,如果他从给定某个城市出发,k天之后到达其它城镇的路径的总和是多少。数据不保证没有重边,也就是说可能每一天从一个城镇到另外一个城镇之间会有多条路径。路径总和可能会非常大,对答案模上1000000007。

输入描述:

NMKSNMKAKSAMuvuv第一行三个整数N,M,K,S分别表示一共有N个城镇,城镇之间有M条单向边。K表示小A连续走K天。S表示小A出发的那个城镇。接下来的M行每行两个整数u,v表示从城镇u连了一条有向边到城镇v。

输出描述:

A一行输出一个结果,表示小A到其余城镇路径数的总和。
示例1

输入

复制
4 5 2 1
1 2
1 3
2 3
4 1
3 4

输出

复制
2

说明

经过2天,小A可以走到3号城镇或者4号城镇,到3号城镇的路径有一条是1-2-3,到4号城镇的路径也是一条是1-3-4,共计有两条路径。

备注:

1N100, 1K1e9

sol:矩阵乘法模板题
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');    return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const ll Mod=1000000007;
const int N=105;
int n,m,A;
ll T;
ll a[N][N],c[N][N],ans[N][N];
inline void Ad(ll &X,ll Y)
{
    X+=Y;
    X-=(X>=Mod)?Mod:0;
    return;
}
int main()
{
    int i,j,k;
    ll Sum;
    R(n); R(m); R(T); R(A);
    for(i=1;i<=m;i++)
    {
        int x,y;
        R(x); R(y);
        a[x][y]++;
    }
    for(i=1;i<=n;i++) ans[i][i]=1;
    while(T)
    {
        if(T&1)
        {
            memset(c,0,sizeof c);
            for(i=1;i<=n;i++) for(j=1;j<=n;j++) for(k=1;k<=n;k++)
            {
                Ad(c[i][j],a[i][k]*ans[k][j]%Mod);
            }
            memmove(ans,c,sizeof ans);
        }
        memset(c,0,sizeof c);
        for(i=1;i<=n;i++) for(j=1;j<=n;j++) for(k=1;k<=n;k++)
        {
            Ad(c[i][j],a[i][k]*a[k][j]%Mod);
        }
        memmove(a,c,sizeof a);
        T>>=1;
    }
    ll res=0;
    for(i=1;i<=n;i++) if(i!=A)
    {
        res+=1ll*ans[A][i]%Mod;
        res-=(res>=Mod)?Mod:0;
    }
    Wl(res);
    return 0;
}
/*
input
4 5 2 1
1 2
1 3
2 3
4 1
3 4
output
2
*/
View Code

 

链接:https://ac.nowcoder.com/acm/contest/549/F
来源:牛客网

小A的最短路
时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小A这次来到一个景区去旅游,景区里面有N个景点,景点之间有N-1条路径。小A从当前的一个景点移动到下一个景点需要消耗一点的体力值。但是景区里面有两个景点比较特殊,它们之间是可以直接坐观光缆车通过,不需要消耗体力值。而小A不想走太多的路,所以他希望你能够告诉它,从当前的位置出发到他想要去的那个地方,他最少要消耗的体力值是多少。

输入描述:

第一行一个整数N代表景区的个数。
接下来N-1行每行两个整数u,v代表从位置u到v之间有一条路径可以互相到达。
接下来的一行两个整数U,V表示这两个城市之间可以直接坐缆车到达。
接下来一行一个整数Q,表示有Q次询问。
接下来的Q行每行两个整数x,y,代表小A的位置在x,而他想要去的地方是y。

输出描述:

x,yxy对于每个询问下x,y输出一个结果,代表x到y消耗的最少体力
示例1

输入

复制
4
1 2
1 3
2 4
3 4
2
1 3
3 4

输出

复制
1
0

备注:

1N3e5 1Q1e6

sol:写个LCA板子, 可以查询树上两点间的距离了,分类讨论三种情况:直接走;一个去A,另一个去B;一个去B,另一个去A
#include<iostream>
#include<cstdio>
using namespace std;
const int N=300005;
struct yyy{
    int t,nex;
}e[N<<1];
int depth[N],fa[N][23],lg[N],head[N];
int tot;
void add(int x,int y) //邻接表存树
{
    e[++tot].t=y; 
    e[tot].nex=head[x];
    head[x]=tot;
}
void dfs(int f,int fath)
{
    depth[f]=depth[fath]+1;
    fa[f][0]=fath;
    for(int i=1;(1<<i)<=depth[f];i++)
      fa[f][i]=fa[fa[f][i-1]][i-1];
    for(int i=head[f];i;i=e[i].nex)
      if(e[i].t!=fath)
        dfs(e[i].t,f);
}
int lca(int x,int y)
{
    if(depth[x]<depth[y])
      swap(x,y);
    while(depth[x]>depth[y])
      x=fa[x][lg[depth[x]-depth[y]]-1];
    if(x==y)
      return x;
    for(int k=lg[depth[x]]-1;k>=0;k--)
      if(fa[x][k]!=fa[y][k])
        x=fa[x][k], y=fa[y][k];
    return fa[x][0];
}
inline int dis(int x,int y)
{
    return depth[x]+depth[y]-2*depth[lca(x,y)];
}
int n,m;
int A,B;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++)
    {
        int x,y;  scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    scanf("%d%d",&A,&B);
    dfs(1,0);
    for(int i=1;i<=n;i++)
      lg[i]=lg[i-1]+(1<<lg[i-1]==i);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int x,y; 
        scanf("%d%d",&x,&y);
        printf("%d\n",min(dis(x,y),min(dis(x,A)+dis(y,B),dis(x,B)+dis(y,A))));
    }
    return 0;
}
/*
input
4
1 2
1 3
2 4
3 4
2
1 3
3 4
output
1
0
*/
View Code

 

链接:https://ac.nowcoder.com/acm/contest/549/G
来源:牛客网

小A与小B
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小A与小B这次两个人都被困在了迷宫里面的两个不同的位置,而他们希望能够迅速找到对方,然后再考虑如何逃离迷宫的事情。小A每次可以移动一个位置,而小B每次可以移动两次位置,小A移动的方向是上下左右左上左下右上右下8个方向,小B移动的方向是上下左右4个方向,请问他们最早什么时候能够找到对方,如果他们最终无法相遇,那么就输出”NO"。

输入描述:

NMN×M"C"A,"D"B"""."第一行两个整数N,M分别表示迷宫的行和列。接下来一个N×M的矩阵其中"C"表示小A的位置,"D"表示小B的的位置,"#"表示不可通过的障碍,"."则是可以正常通过的位置。字符用空格隔开

输出描述:

如果可以相遇,第一行输出一个YES,第二行一个整数输出最短的相遇时间。
否则就输出一个NO表示不能相遇。
示例1

输入

复制
4 5
. . . . .
. # # # .
. . . # D
. . C # .

输出

复制
YES
3

备注:

1n,m1000

sol:双向bfs,A和B都按上述规则一次次走,走到相遇了为止
Ps:实现略烦

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');    return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=1005;
const int dx[]={-1,1,0,0,1,1,-1,-1};
const int dy[]={0,0,-1,1,-1,1,1,-1};
int n,m;
char Map[N][N];
bool Vis[N][N][2];
struct Record
{
    int x,y;
};
queue<Record>Queue[2];
inline bool bfs(int o)
{
    int i;
    queue<Record>CD;
    while(!Queue[o].empty())
    {
        Record tmp=Queue[o].front(); Queue[o].pop();
//        printf("%d : %d %d\n",o,tmp.x,tmp.y);
        for(i=0;i<((o==0)?8:4);i++)
        {
            Record To=tmp; To.x+=dx[i]; To.y+=dy[i];
            if(To.x>=1&&To.x<=n&&To.y>=1&&To.y<=m&&(Map[To.x][To.y]!='#'))
            {
                if(!Vis[To.x][To.y][o])
                {
                    if(Vis[To.x][To.y][o^1]) return true;
                    Vis[To.x][To.y][o]=1;
                    CD.push(To);
                }
            }
        }
    }
    while(!CD.empty())
    {
        Record tmp=CD.front(); CD.pop(); Queue[o].push(tmp);
    }
    return false;
}
int main()
{
    int i,j,x1,y1,x2,y2,ans=0;
    R(n); R(m);
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            char ch=' '; while(ch==' '||ch=='\n') ch=getchar();
            Map[i][j]=ch;
        }
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++) if(isupper(Map[i][j]))
        {
            if(Map[i][j]=='C') x1=i,y1=j;
            else if(Map[i][j]=='D') x2=i,y2=j;
        }
    }
//    printf("%d %d %d %d\n",x1,y1,x2,y2);
    Vis[x1][y1][0]=Vis[x2][y2][1]=1;
    Queue[0].push((Record){x1,y1});
    Queue[1].push((Record){x2,y2});
    bool Bo=0;
    while(Queue[0].size()||Queue[1].size())
    {
        ans++;
        if(bfs(0))
        {
            Bo=1;
            break;
        }
        if(bfs(1))
        {
            Bo=1;
            break;
        }
        if(bfs(1))
        {
            Bo=1;
            break;        
        }
    }
    if(Bo)
    {
        puts("YES");
        Wl(ans);
    }
    else puts("NO");
    return 0;
}
/*
input
4 5
. . . . .
. # # # .
. . . # D
. . C # .
output
YES
3
*/
View Code

 

链接:https://ac.nowcoder.com/acm/contest/549/H
来源:牛客网

小A的柱状图
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

柱状图是有一些宽度相等的矩形下端对齐以后横向排列的图形,但是小A的柱状图却不是一个规范的柱状图,它的每个矩形下端的宽度可以是不相同的一些整数,分别为a[i]a[i],每个矩形的高度是h[i]h[i],现在小A只想知道,在这个图形里面包含的最大矩形面积是多少。


输入描述:

一行一个整数N,表示长方形的个数
接下来一行N个整数表示每个长方形的宽度
接下来一行N个整数表示每个长方形的高度

输出描述:

一行一个整数,表示最大的矩形面积
示例1

输入

复制
7
1 1 1 1 1 1 1
2 1 4 5 1 3 3

输出

复制
8

说明

样例如图所示,包含的最大矩形面积是8

备注:

1n1e6,1a[i]100,1h[i]1e9
sol:单调栈板子题,对于每一根柱子,找到左右两边第一个比它矮的即可,单调栈顶维护最大值

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');    return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=1000005;
int n;
ll a[N],h[N],Qzh[N];
ll Stack[N],Top=0,R[N],L[N];
int main()
{
    int i;
    ll ans=0;
    R(n);
    for(i=1;i<=n;i++) {R(a[i]); Qzh[i]=Qzh[i-1]+a[i];}
    for(i=1;i<=n;i++) R(h[i]);
    for(i=1;i<=n;i++) ans=max(ans,a[i]*h[i]);
    for(i=1;i<=n;i++)
    {
        while(Top&&h[Stack[Top]]>h[i])
        {
            R[Stack[Top]]=i;
            Top--;
        }
        L[i]=Stack[Top]+1;
        Stack[++Top]=i;
    }
    for(i=1;i<=n;i++)
    {
        if(R[i]==0) R[i]=n+1;
        ans=max(ans,(Qzh[R[i]-1]-Qzh[L[i]-1])*h[i]);
    }
    Wl(ans);
    return 0;
}
/*
input
7
1 1 1 1 1 1 1
2 1 4 5 1 3 3
output
8
*/
View Code

 

链接:https://ac.nowcoder.com/acm/contest/549/I
来源:牛客网

小A取石子
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

小A也听说了取石子这个游戏,也决定和小B一起来玩这个游戏。总共有n堆石子,双方轮流取石子,每次都可以从任意一堆中取走任意数量的石子,但是不可以不取。规定谁先取完所有的石子就获胜。但是小A实在是太想赢了,所以在游戏开始之前,小A有一次机会,可以趁小B不注意的时候选择其中一堆石子拿走其中的k个,当然小A也可以选择不拿石子。小A先手。双方都会选择最优的策略,请问在这样的情况下小A有没有必胜的策略,如果有输出YES,否则就输出NO。

输入描述:

一行两个整数N,K,表示分别有N堆石子以及小A可以拿走的石子个数k。
接下来N个整数表示每一堆的石子个数aiai

输出描述:

一行一个结果表示小A是否有必胜策略,如果有则输出YES,否则输出NO。
示例1

输入

复制
3 2
1 1 1

输出

复制
YES

备注:

1n1e51ai1e50k1e5

sol:非常easy的博弈论啊
查询是否有一堆取走K个后所有数异或和非0,或者原来的异或和就非0即可
#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');    return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=100005;
int n,K,a[N];
int main()
{
    int i,Xor=0;
    R(n); R(K);
    for(i=1;i<=n;i++)
    {
        R(a[i]);
        Xor^=a[i];
    }
    if(!Xor)
    {
        for(i=1;i<=n;i++) if(a[i]>=K)
        {
            if(Xor^a[i]^(a[i]-K)) return 0*puts("YES");
        }
        puts("NO");
    }
    else puts("YES");
    return 0;
}
/*
input
3 2
1 1 1
output
YES
*/
View Code

 

J题留坑

 

posted @ 2019-04-18 21:32  yccdu  阅读(320)  评论(0编辑  收藏  举报