Codeforces Round #432 C. Arpa and a game with Mojtaba 裸博弈+质数拆解

来源:互联网 发布:万象数据库默认密码 编辑:程序博客网 时间:2024/05/22 00:12

原题链接:codeforces.com/problemset/problem/850/C

题目大意:给出一个数列,游戏规则如下:1.每个人选择一个质数p和正整数k,然后使得数列中所有是p的k次方的倍数的元素除以p的k次方;2.两个玩家轮流进行上述操作,某个玩家无法进行上述操作时,该名玩家失败,游戏结束。

先让我哭一会QAQ ,我当时应该先看这道题的呀,这题我用了50min左右就过了,结果去写D还少个if直接TLE。

显然,在操作的过程中每个质数之间是互不影响的,所以可以把每个元素拆分成不同质数的乘积,把每个质数单独处理,比如数列 2 4 10 15 6 可以拆分为 2 4 2 1 2 和 1 1 5 5 1 和 1 1 1 3 3 三个数列,把这三个数列看成不相影响的游戏。再因为SG函数的性质,总游戏的SG值=子游戏的SG值的异或和。所以只要分别求出这三个局面的SG值就可以获得总游戏的SG值了。

如何获得单个游戏的SG值呢,因为元素值小于10^9,所以如果把拆分后的数列对 对应的质数取log的话,最大的元素值不会超过 30,这就很方便了。

因为拆分后的数列的相同元素肯定会被同时消去,所以就没有必要记录相同元素出现的次数,只要记录质数q的某个幂次是否出现过,于是可以采用二进制状态压缩的方法用int就可以存下。

至于复杂度的话,好像是因为操作非常容易到达相同的状态所以复杂度就比较低

代码:

#include <bits/stdc++.h>using namespace std;inline void read(int &x){    char ch;    bool flag=false;    for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;    for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());    x=flag?-x:x;}inline void read(long long &x){    char ch;    bool flag=false;    for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;    for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());    x=flag?-x:x;}int const maxn=1000;int a[maxn];int n;int num[maxn];map <int ,int > M;int lowbit(int x){return x&(-x);}int dfs(int x){if (M.count( x ) !=0 )    return M[x];bool vis[10000];memset(vis,0,sizeof(vis));int tmp=x;int now=( 1<<29 );while(  ( x & now ) ==0)    now=now/2;while (now!=1)    {        tmp=(x%now)| (x/now);        //printf("%d %d  %d\n",x,tmp,now);        //system("pause");        vis[ dfs( tmp ) ]=1;        now=now/2;    }for (int i=0;;i++)    if (vis[i]==0)        {            M[x]=i;            return i;        }}int get_num( int &x ,int v){int tmp=0;while ( x% v==0)    {        tmp++;        x=x/v;    }return tmp;}int main(){    M[1]=0;    read(n);    for (int i=1;i<=n;i++)        read(a[i]);    int ans=0;    for (int i=1;i<=n;i++)        {            int tmp=a[i];            for (int j=2;j<=sqrt(tmp);j++)                {                    if ( j> sqrt( a[i] ) )                        break;                    if ( a[i]%j==0)                        {                            int now=0;                            for (int k=1;k<=n;k++)                                now=now|( 1<< ( get_num( a[k] , j ) ) );                            int t=dfs(now);                            ans=ans^t;                        }                }            if ( a[i]!=1)                {                    int now=0;                    int j=a[i];                    for (int k=1;k<=n;k++)                        now=now|( 1<< ( get_num( a[k] , j ) ) );                    int t=dfs(now);                    ans=ans^t;                }        }    if (ans)        puts("Mojtaba");    else        puts("Arpa");    return 0;}


阅读全文
0 0
原创粉丝点击