数学カウント-2013 ACM/ICPC Asia Regional Changsha Online-Gタイトル

3964 ワード

テーマリンク:
http://acm.zju.edu.cn/changsha/showProblem.do?problemCode=G
タイトルの大意:
一つの数x(1<=x==80000)をあげて、2種類の運算で足し算と掛け算をすることができて、最大3つの素数を使って聞いて、xに集まって全部でどれだけの方法がありますか?
問題解決の考え方:
数学の数
素数フィルタを使って素数を絞り出します。全部で8000個しかないので、o(n^2)を使ってもいいです。
それから状況によって討論します。
1、掛け算だけで、一つの素数が掛け合われ、二つの素数が掛け合われ、三つの素数が掛け合われます。注意は素数を掛け合わせることです。
2、かけ算があります。一つの素数を差し引き、二つの素数を掛け合わせることができるかどうかを判断します。
3、3つの素数の加算。三つの場合に分けて、待ちたくないです。同じ二つがあります。三つとも同じです。
4、2つの素数の加算。二つの場合に分けて、等しくない、等しい。
先に前処理して、二つの異なる素数からなるのとiの種数で、同じ種数です。
コードの説明はとても詳しいです。
コード:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 81000

bool prime[Maxn];
int pp[8000],cnt; //       7378 
int num1[200000],num2[200000]; //num1[i]    i            
//num2[i]    i             
void init()
{
    memset(prime,true,sizeof(prime));
    prime[0]=0;
    prime[1]=0;
    int n=80000;
    for(int i=2;i<=sqrt(n*1.0);i++)
    {
        if(prime[i])
        {
            for(int j=i*2;j<=n;j+=i)
                prime[j]=0;
        }
    }
    cnt=0;
    for(int i=2;i<=n;i++)
        if(prime[i])
            pp[++cnt]=i;
    for(int i=1;i<=cnt;i++) //o(8000^2) 8s    
        for(int j=i+1;j<=cnt;j++)
            num1[pp[i]+pp[j]]++;
    for(int i=1;i<=cnt;i++)
        num2[pp[i]+pp[i]]++;
    //printf("%d
",cnt); } int mul(int n,int num)// num n { if(prime[n]) // { if(num==1) return 1; else return 0; } int res=0; for(int i=1;pp[i]*pp[i]<=n&&i<=cnt;i++) { while(n%pp[i]==0) { n/=pp[i]; res++; if(res>num) return 0; } } if(n!=1) res++; if(res==num) return 1; return 0; } int main() { init(); int x; ll ans; while(~scanf("%d",&x)) { ans=0; ans+=mul(x,1); // ans+=mul(x,2); // ans+=mul(x,3); // // for(int i=1;i<=cnt;i++) { int t=x-pp[i]; if(t<4) break; ans+=mul(t,2); } // // ll temp=0; for(int i=1;i<=cnt;i++) { int t=x-pp[i]; // if(t>=2) { if(t-pp[i]>=2&&prime[t-pp[i]]) { if(x==pp[i]*3) // pp[i] temp+=num1[t]; else temp+=num1[t]-1; // pp[i] } else temp+=num1[t]; } else break; } ans+=temp/3; // // , for(int i=1;i<=cnt;i++) { int t=x-pp[i]*2; if(t>=2) { if(prime[t]) { if(t!=pp[i]) ans++; } } else break; } // for(int i=1;i<=cnt;i++) { if(x>=pp[i]*3) { if(x==pp[i]*3) ans++; } else break; } // // ans+=num1[x]; // ans+=num2[x]; printf("%lld
",ans); } return 0; }