absi2011's Blog & Daily Life.

全新的开始       我要省选翻盘       I wanna AK in 高考\化学       自此,生无可恋
[破碎的状态] [-64] NOI 2015 品酒大会
[破碎的状态] [-60] [WC2014]非确定机

[破碎的状态] [-63] NOI 2015 寿司晚宴

absi2011 posted @ May 20, 2016 12:36:48 PM in 刷题记录 with tags uoj 小高考 , 578 阅读

讲道理,这题和那题做出来我离Au就不远了....(差3分!)

考试的时候好sb啊..现在回想起来并不难弄..?

我在NOI上就思考到,232=529>500

那么对于一个数x,一定能表示成一个质数p(或者1)和前8个质数的乘积的形式

例如 46 = 2 * 23

我们接下来3^8大暴力

我们可以发现,对于一个数,如果它是前8个质数乘起的,我们可以判定出它能不能被选(如果能,答案*2,如果不能..答案不变)

如果是p*前8个数,我们先看它能不能选,能选我们记录下来,考虑p及其倍数时候,如果第一个人选有多少可选,第二个人选有多少可选

我们可以发现,这个p的选择方案就是2^第一个人有多少可以选+2^第二个人有多少可以选-1

我们这么理解:第一个人选或不选他所有的,第二个人选或不选他所有的,分别是2的若干次方,至于-1就是..都不选的情况

那么,代码如下:

#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<string>
#include<time.h>
#include<bitset>
#include<vector>
#include<memory>
#include<utility>
#include<stdio.h>
#include<sstream>
#include<fstream>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
int prime[11]={2,3,5,7,11,13,17,19};
int primes[105];
bool is_prime(int x)
{
    int i;
    for (i=2;i*i<=x;i++)
    {
        if (x%i==0) return false;
    }
    return true;
}
int val[505];
int leave[505];
int cnt1[505],cnt2[505];
int power(int x,int y,int p)
{
    if (y==0) return 1;
    int t=power(x,y/2,p);
    t=(long long)t*t%p;
    if (y%2==1) t=(long long)t*x%p;
    return t;
}
int main()
{
    int n,p;
    scanf("%d%d",&n,&p);
    int i;
    int sum=0;
    for (i=23;i<=n;i++)
    {
        if (is_prime(i)) primes[sum++]=i;
    }
    for (i=2;i<=n;i++)
    {
        int j;
        int t=i;
        for (j=0;j<8;j++)
        {
            if (i%prime[j]==0)
            {
                val[i]^=(1<<j);
            }
            for (;t%prime[j]==0;) t/=prime[j];
        }
        leave[i]=t;
    }
    int j;
    int ans=0;
    for (i=0;i<(1<<8);i++)
    {
        for (j=0;j<(1<<8);j++)
        {
            if (i&j) continue;
            int k;
            int flag=1;
            for (k=0;k<8;k++)
            {
                if ((1<<k)&(i|j)) flag*=-1;
            }
            for (k=1;k<=n;k++)
            {
                cnt1[k]=0;
                cnt2[k]=0;
            }
            for (k=2;k<=n;k++)
            {
                if ((val[k]&i)==val[k]) cnt1[leave[k]]++;
                if ((val[k]&j)==val[k]) cnt2[leave[k]]++;
            }
            int anses=1;
            for (k=0;k<sum;k++)
            {
                anses=(long long)anses*((1<<cnt1[primes[k]])+(1<<cnt2[primes[k]])-1)%p;
            }
            anses=(long long)anses*power(2,cnt1[1]+cnt2[1],p)%p;
            ans+=anses*flag;
            ans%=p;
        }
    }
    printf("%d\n",(ans+p)%p);
    //system("pause");
    return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter