[HAOI2015]数组游戏

时间:2019-08-30
本文章向大家介绍[HAOI2015]数组游戏,主要包括[HAOI2015]数组游戏使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

emmm这道题讲真是一道动态规划的题目,然而这道题你打暴力也有70分,但是如果你dp学得还不错的话这道题目的代码实现其实并不难,甚至说,比暴力还容易些。

本题提供两种写法:

暴力做法:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define LL long long
#define inf 0x3f3f3f3f
#define maxn 100005
using namespace std;
int gi()
{
    int res=0,s=1; char ch;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-') s=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) res=res*10+ch-48;
    return res*s;
}
int n,cnt,mk[100];
int lef[100005],rig[100005],sg[100005],SG[100005];
int ask(int x) {
    if(n/x<=maxn) return sg[n/x];
    else return SG[n/(n/x)];
}
void ins(int x,int v) {
    if(n/x<=maxn) sg[n/x]=v;
    else SG[n/(n/x)]=v;
}
int work(int x) {
    memset(mk,0,sizeof(mk)); mk[0]=1;
    int m=n/x,sum=0,val;
    for(int i=2,pos=1;i<=m;i=pos+1) {
    pos=m/(m/i),val=ask(x*pos);
    mk[sum^val]=1;
    if((pos-i+1)&1) sum^=val;
    }
    for(int i=0;;++i) if(!mk[i]) return i;
}
int main()
{
    n=gi();
    for(int i=1,pos=0;i<=n;i=pos+1)
    pos=n/(n/i),lef[++cnt]=i,rig[cnt]=pos;
    for(int i=cnt;i;--i)
    ins(rig[i],work(rig[i]));
    for(int k=gi();k;--k) {
    int num=gi(),res=0;
    for(int x;num;--num)
        x=gi(),res^=ask(x);
    printf("%s",res?"Yes\n":"No\n");
    }
    return 0;
}

然而暴力只能过样例,打表才能出奇迹,咳咳,下面是正经做法:

正常做法:

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=500005;
int n,Q,ans,b[maxn],c[2][maxn],vis[maxn],clk,sqrt_n;
inline int getSG(int x){
    x=n/(n/x);
    if(x<=sqrt_n) return c[0][x]; else return c[1][n/x];
}
void Solve(){
    for(int i=1;i<=n;i=n/(n/i)+1) b[++b[0]]=n/(n/i);
    for(int i=b[0];i>=1;i--){
        int x=b[i],now=0; clk++; vis[0]=clk; 
        for(int j=x+x;j<=n;){
            int t=(n/(n/j))/x*x, cnt=(t-j)/x+1;
            vis[now^getSG(j)]=clk;
            if(cnt&1) now^=getSG(j);
            j=t+x;
        }
        int res=0; while(vis[res]==clk) res++;
        if(x<=sqrt_n) c[0][x]=res; else c[1][n/x]=res;
    }
}
int main(){
    scanf("%d",&n); sqrt_n=sqrt(n)+1;
    Solve();
    scanf("%d",&Q);
    while(Q--){
        int t,x; scanf("%d",&t); ans=0;
        while(t--) scanf("%d",&x), ans^=getSG(x);
        if(ans) puts("Yes"); else puts("No");
    }
    return 0;
}

怎么样,是不是正常写法比暴力还容易些?

原文地址:https://www.cnblogs.com/zi-nai-boboyang/p/11437190.html