math

T2:

问题描述

给你一个除法表达式:X1/X2/X3/X4……/Xk 其中Xi是正整数并且 Xi <= 2 000 000 000( 1<=i<=k,k<=10 000 )。除法表达式应当按照从左到右的顺序求结果,例如:表达式1/2/1/2的值是1/4,你可以在表达E中嵌入括号改变计算顺序,例如表达式(1/2)/(1/2)的值是1。现在给你一个除法表达式E,计算是否能够通过加括号(或者不加)得到表达式E' ,E'的值为整数。

输入文件

输入数据包括多组数据,每组数据占一行,给出的是题目描述的表达式E,E中不含空格。

输出文件

每组测试数据占一行如果能找到题目中描述的E' 则输出"YES"(不含引号),否则输出"NO" (不含引号)。

样例输入

1/2/1/2
2/3

样例输出

YES
NO

限制与约定

时间限制:1s

空间限制:128MB

思路 :第二个放在分母上,其他的都可以放在分子上。。。超int。。。

std:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e4+5;
char ch[maxn*15];
int a[maxn],temp,k;
inline int read(){
    int a=0;
    while(ch[temp]<'0'||'9'<ch[temp])temp++;
    while('0'<=ch[temp]&&ch[temp]<='9'){
        a=(a<<1)+(a<<3)+ch[temp++]-'0';    
    } 
    return a; 
}
int main(){
    while(scanf("%s",ch+1)>0){
        int len=strlen(ch+1);
        temp=1;k=0; 
        for(int i=1;ch[temp]!='\0';i++,k++){
            a[i]=read();
            //printf("%d ",a[i]);
        }
        for(int i=1;i<=k;i++){
            if(i!=2){
                int d=__gcd(a[i],a[2]);//使用gcd约分,注意别超int。。。
                a[2]/=d;//第二个数一定是分母
            }
        }
        printf(a[2]==1?"YES\n":"NO\n");
    }
    return 0;
}

 组合数:
使用阶乘以及逆元的运算:

std:

#define LL long long
#include<cstdio>
#include<algorithm>
using namespace std;
const int P=1000000007;
const int maxn=1000000+5;
int n,a,b,x,y,d;
void exgcd(int a,int b){
    if(!b){
        d=a;x=a;y=0;
        return;
    }
    exgcd(b,a%b);//bx+(a-qb)y=0 -> ay+b(x-qy)=0;
    int t=y;
    y=(x-(a/b)*y);
    x=t;
}
inline int get_inv(int a){
    exgcd(a,P);//注意顺序 
    return (x%P+P)%P;
}
//以上是求解逆元的 拓展欧几里得算法
int inv[maxn],jc[maxn],njc[maxn]; inline void inv_init(){ inv[1]=jc[1]=njc[1]=1; for(int i=2;i<=n;i++){ inv[i]=1ll*(P-P/i)*inv[P%i]%P;//当p为质数时成立的递推公式 jc[i]=1ll*jc[i-1]*i%P; njc[i]=1ll*njc[i-1]*inv[i]%P;// } } inline LL C(int m,int n){ return 1ll*jc[n]%P*njc[n-m]%P*njc[m]%P; } int main(){ scanf("%d%d%d",&n,&a,&b); inv_init(); printf("%lld",C(min(a,b), return 0; }

eular 函数:

#include<cstdio>
using namespace std;
const int maxn=1000000+5;
int phi[maxn],n;
inline void get_phi(){
    for(int i=1;i<=n;i++)phi[i]=i;
    for(int i=2;i<=n;i++){
        if(phi[i]==i){
            for(int j=1;j*i<=n;j++){
                phi[j*i]=phi[j*i]/i*(i-1);//埃氏筛,较慢
            }
        }
    }
    return;
}
inline void 
int main(){
    scanf("%d",&n);
    get_phi();
    for(int i=1;i<=n;i++){
        printf("%d\n",phi[i]);
    }
    return 0;
}

 线性筛(eular 筛)

std:

#include<cstdio>
using namespace std;
const int maxn=1000000+5;
int phi[maxn],n,cnt,prime[maxn];
bool flag[maxn];
inline void get_phi(){
    for(int i=1;i<=n;i++)phi[i]=i;
    for(int i=2;i<=n;i++){
        if(phi[i]==i){
            for(int j=1;j*i<=n;j++){
                phi[j*i]=phi[j*i]/i*(i-1);
            }
        }
    }
    return;
}
inline void phi_init(){
    /*for(int i=1;i<=n;i++){
        phi[i]=i;
    }*/
    phi[1]=1;
    for(int i=2;i<=n;i++){
        if(!flag[i]){//is prime
            prime[++cnt]=i;
            phi[i]=i-1;
            
            for(int j=1;j<=cnt;j++){
                int t=prime[j]*i;
                if(t>n)break;
                flag[t]=1;
                
                phi[t]=phi[i]*( (j==cnt) ? prime[j] : (prime[j]-1) );//积性函数 
            }
            
        }
        else{
            for(int j=1;j<=cnt;j++){
                int t=prime[j]*i;
                if(t>n)break;
                flag[t]=1;
                if(i%prime[j]==0){//eular 定理推论
                    phi[t]=phi[i]*prime[j];
                    break;
                }
                else{
                    phi[t]=phi[i]*(prime[j]-1);
                }
            }
        }
    }
}
int main(){
    scanf("%d",&n);
    phi_init();
    for(int i=1;i<=n;i++){
        printf("%d\n",phi[i]);
    }
    return 0;
}

 

273. 古代猪文(BZOJ1951)

问题描述

猪王国的文明源远流长,博大精深。 iPig在大肥猪学校图书馆中查阅资料,得知远古时期猪文文字总个数为N。当然,一种语言如果字数很多,字典也相应会很大。当时的猪王国国王考虑到如果修一本字典,规模有可能远远超过康熙字典,花费的猪力、物力将难以估量。故考虑再三没有进行这一项劳猪伤财之举。当然,猪王国的文字后来随着历史变迁逐渐进行了简化,去掉了一些不常用的字。 iPig打算研究古时某个朝代的猪文文字。根据相关文献记载,那个朝代流传的猪文文字恰好为远古时期的k分之一,其中k是N的一个正约数(可以是1和N)。不过具体是哪k分之一,以及k是多少,由于历史过于久远,已经无从考证了。 iPig觉得只要符合文献,每一种能整除N的k都是有可能的。他打算考虑到所有可能的k。显然当k等于某个定值时,该朝的猪文文字个数为N / k。然而从N个文字中保留下N / k个的情况也是相当多的。iPig预计,如果所有可能的k的所有情况数加起来为P的话,那么他研究古代文字的代价将会是G的P次方。 现在他想知道猪王国研究古代文字的代价是多少。由于iPig觉得这个数字可能是天文数字,所以你只需要告诉他答案除以999911659的余数就可以了。

输入数据

有且仅有一行:两个数N、G,用一个空格分开。

输出数据

有且仅有一行:一个数,表示答案除以999911659的余数。(无行末回车)。

样例输入1

4 2

样例输出1

2048

样例输入2

6 3

样例输出2

426896497

限制与约定

10%的数据中,1 <= N <= 50;

20%的数据中,1 <= N <= 1000;

40%的数据中,1 <= N <= 100000;

100%的数据中,1 <= G <= 1000000000,1 <= N <= 1000000000。

时间限制:1s

空间限制:64MB

wa:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<iostream>
#define LL long long 
using namespace std;
template<typename T>
inline void read(T &a){
    a=0;bool b=0;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    }
    if(b)a=-a;
}
char C[50];
int temp;
template <typename T>
inline void write(T a){
    if(a<0){
        a=-a;
        putchar('-');
    }
    do{
        C[++temp]=a%10+'0';
        a/=10;
    }while(a);
    while(temp)putchar(C[temp--]);
}
const LL P=999911659;
const LL phi=999911659-1;
LL p[5]={2,3,4679,35617},jc[5][40000],njc[5][40000],inv[5][40000];

LL n,g,pp;

inline LL quickpow(LL a,LL n){//a^n % P
    LL ans=1ll;
    while(n){
        if(n&1)ans=ans*a%P;
        a=a*a%P;
        n>>=1;
    }
    return ans;
}

inline void com_init(int i){
    jc[i][1]=njc[i][1]=inv[i][1]=1ll;
    
    for(int j=2;j<=p[i];j++){//递推 预处理 
        inv[i][j]=( p[i] - p[i] / j )*inv[i][ p[i] % j ]%p[i];
        njc[i][j]=njc[i][j-1]*inv[i][j]%p[i];
        jc[i][j]=jc[i][j-1]*j%p[i];
    }
}
inline LL c(LL n,LL m,int i){
    return jc[i][n]*njc[i][m]%p[i]*njc[i][n-m]%p[i];
}
/*
lucas
*/ LL lucas(LL n,LL m,
int i){ if(n<=p[i]&&m<=p[i])return c(n,m,i); else return 1ll*c(n%p[i],m%p[i],i)*lucas(n/p[i],m/p[i],i); } LL x,y; inline void exgcd(LL a,LL b){ if(!b){ x=1; y=0; return; } exgcd(b,a%b); LL temp=y; y=x-a/b*y; x=temp; } inline LL get_inv(LL a,LL p){ exgcd(a,p); return (x%p+p)%p; } LL Mi[5],nMi[5]; inline void CRT_init(){ for(int i=0;i<4;i++){ Mi[i]=phi/p[i]; nMi[i]=get_inv(Mi[i],p[i]); } } inline LL CRT(LL n,LL m){ LL ans=0ll; for(int i=0;i<4;i++){ ans+=lucas(n,m,i)*Mi[i]%phi*nMi[i]%phi; } return ans; } int main(){ read(n);read(g);//write(n);write(g); for(int i=0;i<4;i++)com_init(i); CRT_init(); for(LL i=1;i*i<=n;i++){//求 sum( C(n,k) , k|n ) if(n%i==0){ pp=(pp+CRT(n,i)+CRT(n,n/i))%phi; } } write(pp); //write(quickpow(g%P,pp)); return 0; }

 ?:

lucas+CRT+Eular:

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<iostream>
#define LL long long 
using namespace std;
template<typename T>
inline void read(T &a){
    a=0;bool b=0;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    }
    if(b)a=-a;
}
char C[50];
int temp;
template <typename T>
inline void write(T a){
    if(a<0){
        a=-a;
        putchar('-');
    }
    do{
        C[++temp]=a%10+'0';
        a/=10;
    }while(a);
    while(temp)putchar(C[temp--]);
}
const LL P=999911659;
const LL phi=999911659-1;
LL p[5]={2,3,4679,35617},jc[5][40000],njc[5][40000],inv[5][40000];

LL n,g,pp;

inline LL quickpow(LL a,LL n){//a^n % P
    LL ans=1ll;
    while(n){
        if(n&1)ans=ans*a%P;
        a=a*a%P;
        n>>=1;
    }
    return ans;
}

inline void com_init(int i){
    jc[i][1]=njc[i][1]=inv[i][1]=1ll;
    
    for(int j=2;j<=p[i];j++){//递推 预处理 
        inv[i][j]=( p[i] - p[i] / j )*inv[i][ p[i] % j ]%p[i];
        njc[i][j]=njc[i][j-1]*inv[i][j]%p[i];
        jc[i][j]=jc[i][j-1]*j%p[i];
    }
}
inline LL c(LL n,LL m,int i){
    return jc[i][n]*njc[i][m]%p[i]*njc[i][n-m]%p[i];
}
LL lucas(LL n,LL m,int i){
    if(n<=p[i]&&m<=p[i])return c(n,m,i);
    else return 1ll*c(n%p[i],m%p[i],i)*lucas(n/p[i],m/p[i],i);
}
LL x,y;
inline void exgcd(LL a,LL b){
    if(!b){
        x=1;
        y=0;
        return;
    }
    exgcd(b,a%b);
    LL temp=y;
    y=x-a/b*y;
    x=temp;
}
inline LL get_inv(LL a,LL p){
    exgcd(a,p);
    return (x%p+p)%p;
}
LL Mi[5],nMi[5];
inline void CRT_init(){
    for(int i=0;i<4;i++){
        Mi[i]=phi/p[i];
        nMi[i]=get_inv(Mi[i],p[i]);
    }
}
inline LL CRT(LL n,LL m){
    LL ans=0ll;
    for(int i=0;i<4;i++){
        ans+=lucas(n,m,i)*Mi[i]%phi*nMi[i]%phi;//运算顺序先后。。。
    }
    return ans;
}
int main(){
    read(n);read(g);//write(n);write(g);
    
    for(int i=0;i<4;i++)com_init(i);
    CRT_init();
    
    for(LL i=1;i*i<=n;i++){//求 sum( C(n,k)  , k|n )
        if(n%i==0){
            pp=(pp+CRT(n,i))%phi;
            if(i*i!=n)
            pp=(pp+CRT(n,n/i))%phi;
            //pp=(pp+CRT(n,i)+CRT(n,n/i))%phi;
        }
    }
    write(pp);
    //write(quickpow(g%P,pp));
    return 0;
}

AC:但洛谷过不去?应该特判???

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<iostream>
#define LL long long 
using namespace std;
template<typename T>
inline void read(T &a){
    a=0;bool b=0;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    }
    if(b)a=-a;
}
char C[50];
int temp;
template <typename T>
inline void write(T a){
    if(a<0){
        a=-a;
        putchar('-');
    }
    do{
        C[++temp]=a%10+'0';
        a/=10;
    }while(a);
    while(temp)putchar(C[temp--]);
}
const LL P=999911659;
const LL phi=999911659-1;
LL p[5]={2,3,4679,35617},jc[5][40000],njc[5][40000],inv[5][40000];

LL n,g,pp;

inline LL quickpow(LL a,LL n){//a^n % P
    LL ans=1ll;
    while(n){
        if(n&1)ans=ans*a%P;
        a=a*a%P;
        n>>=1;
    }
    return ans;
}

inline void com_init(int i){
    
    jc[i][0]=njc[i][0]=inv[i][0]=jc[i][1]=njc[i][1]=inv[i][1]=1ll;
    //0的阶乘及逆元都会用到,初始化为1
    for(int j=2;j<=p[i];j++){//递推 预处理 
        inv[i][j]=( p[i] - p[i] / j )*inv[i][ p[i] % j ]%p[i];
        njc[i][j]=njc[i][j-1]*inv[i][j]%p[i];
        jc[i][j]=jc[i][j-1]*j%p[i];
    }
}
inline LL c(LL n,LL m,int i){
    return jc[i][n]*njc[i][m]%p[i]*njc[i][n-m]%p[i];
}
LL lucas(LL n,LL m,int i){
    if(n<p[i] && m<p[i])return c(n,m,i);
    else return 1ll*c(n%p[i],m%p[i],i)*lucas(n/p[i],m/p[i],i);
}
LL x,y;
inline void exgcd(LL a,LL b){
    if(!b){
        x=1;
        y=0;
        return;
    }
    exgcd(b,a%b);
    
    LL temp=y;
    y=x-a/b*y;
    x=temp;
}
inline LL get_inv(LL a,LL p){
    exgcd(a,p);
    return (x%p+p)%p;
}
LL Mi[5],nMi[5];
inline void CRT_init(){
    for(int i=0;i<4;i++){
        Mi[i]=phi/p[i];
        nMi[i]=get_inv(Mi[i],p[i]);
    }
}
inline LL CRT(LL n,LL m){
    LL ans=0ll;
    for(int i=0;i<4;i++){
        ans=(ans+lucas(n,m,i)*Mi[i]%phi*nMi[i])%phi;
    }
    return ans;
}
int main(){
    read(n);read(g);
    
    for(int i=0;i<4;i++)com_init(i);
    CRT_init();
    
    for(LL i=1;i*i<=n;i++){//求 sum( C(n,k)  , k|n )
        if(n%i==0){
            pp=(pp+CRT(n,i))%phi;
            if(i*i!=n)
            pp=(pp+CRT(n,n/i))%phi;
        }
    }
    write(quickpow(g%P,pp));
    return 0;
}

std:

notice the detail:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<iostream>
#define LL long long 
using namespace std;
template<typename T>
inline void read(T &a){
    a=0;bool b=0;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    }
    if(b)a=-a;
}
char C[50];
int temp;
template <typename T>
inline void write(T a){
    if(a<0){
        a=-a;
        putchar('-');
    }
    do{
        C[++temp]=a%10+'0';
        a/=10;
    }while(a);
    while(temp)putchar(C[temp--]);
}
const LL P=999911659;
const LL phi=999911659-1;
LL p[5]={2,3,4679,35617},jc[5][40000],njc[5][40000],inv[5][40000];

LL n,g,pp;

inline LL quickpow(LL a,LL n){//a^n % P
    LL ans=1ll%P;
    while(n){
        if(n&1)ans=ans*a%P;
        a=a*a%P;
        n>>=1;
    }
    return ans;
}

inline void com_init(int i){
    
    jc[i][0]=njc[i][0]=jc[i][1]=njc[i][1]=inv[i][1]=1ll%P;
    
    for(int j=2;j<=p[i];j++){//递推 预处理 
        inv[i][j]=( p[i] - p[i] / j )*inv[i][ p[i] % j ]%p[i];
        njc[i][j]=njc[i][j-1]*inv[i][j]%p[i];
        jc[i][j]=jc[i][j-1]*j%p[i];
    }
    
}
inline LL c(LL n,LL m,int i){
    if(n==m || !m)return 1ll;
    return jc[i][n]*njc[i][m]%p[i]*njc[i][n-m]%p[i];
}
/*
!!!lucas绝对不能这么写!!!
LL Lucas(LL n,LL m,LL p)//Lucas定理
{
    if(n<m) return 0;if(!m) return 1;
    return Lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;//可能会出现  a>b 但是 a%p < b%p
}
*/
/*
lucas还能这么写
inline LL lucas(LL n,LL m,LL p){
    /*if(m>n)return 0;
    if(!m)return 1;
    if(n<p && m<p)return C(n,m,p)%p;
    else return 1ll*lucas(n%p,m%p,p)*lucas(n/p,m/p,p)%p;*/
    LL ans=1ll;
    while(n&&m){
        LL N=n%p,M=m%p;
        if(N<M)ans=0;
        else   ans=ans*C(N,M,p)%p;
        
        n/=p;
        m/=p;
    }
    return ans;
}
*/
LL lucas(LL n,LL m,
int i){ if(m>n)return 0; if(n<=p[i] && m<=p[i])return c(n,m,i)%p[i]; else return 1ll*lucas(n%p[i],m%p[i],i)*lucas(n/p[i],m/p[i],i)%p[i]; } LL x,y; inline void exgcd(LL a,LL b){ if(!b){ x=1; y=0; return; } exgcd(b,a%b); LL temp=y; y=x-a/b*y; x=temp; } inline LL get_inv(LL a,LL p){ exgcd(a,p); return (x%p+p)%p; } LL Mi[5],nMi[5]; inline void CRT_init(){ for(int i=0;i<4;i++){ Mi[i]=phi/p[i]; nMi[i]=get_inv(Mi[i],p[i]); } } inline LL CRT(LL n,LL m){ LL ans=0ll; for(int i=0;i<4;i++){ ans=(ans+lucas(n,m,i)*Mi[i]%phi*nMi[i]%phi)%phi; } return ans; } int main(){ read(n);read(g); if(g==P){ /*!!!Eular定理适用范围:a^phi(m) % m=1 当且仅当(a,m)=1时成立 本题没有说明这个条件,所以即使p时质数也要特判!!! */ write(0); return 0; } for(int i=0;i<4;i++)com_init(i); CRT_init(); for(LL i=1;i*i<=n;i++){//求 sum( C(n,k) , k|n ) if(n%i==0){ pp=(pp+CRT(n,i))%phi; if(i*i!=n) pp=(pp+CRT(n,n/i))%phi; } } write(quickpow(g%P,pp)); return 0; }

 

268. Saving Beans(HDU3037)

题目描述

虽然冬天很远,松鼠却不得不日夜工作来保存豆子。他们需要足够的食物度过那些漫长的寒冷日子。一段时间后,松鼠家族认为他们必须解决一个问题。他们认为他们可以在不同的树中保存豆子。然而,由于现在食物不够,他们得到的只会是豆子。他们想知道有多少种方法可以在N棵树中保存不超过M个豆子(它们是相同的)。

输入格式

第一行包含一个整数t,表示案例数, 接下来t行,每行包含三个整数N,M,P,这意味着松鼠在N个不同的树中保存的豆子不会超过M。

输出格式

方案数%p

样例输入

2
1 2 5
2 1 5

样例输出

3
3

数据范围

1<=n,m<=10^9,1 < p < 10^5,保证p是素数

时间限制:1s

空间限制:128MB

 

#259. 无平方因子的个数

问题描述

给出正整数n和m,求区间[n,m]内的“无平方因子”的数有多少个?

整数p无平方因子当且仅当不存在k > 1,使得p是k * k的倍数。

样例输入

1 10

样例输出

7

限制与约定

1 <= n <= m <= 10 ^ 12,m - n <= 10 ^ 7

时间限制:1s

空间限制:128MB

 

无平方因子的个数
思路分析:
分析最坏情况[1, 10 ^ 12],如果一个个判断的话,显然时间太大,
就算如题意m - n最大值为10 ^ 7,那样也会超时,所以我们考虑其它方法,
即筛选法,考虑这种方法时,我们要把题目中的条件做一下逆向转换,
也就是说对于一个数p,如果其2p*p,3p*p存在与上述范围内
,则他们就不是无平方因子,有没有发现这个和 素数筛法 很像
,Right,我们总结一下,他们都有一个条件,这个条件我们把它称为正条件
,我们必须能够转化出逆条件。
1.这个逆条件以某些数为起始,这些起始数一定符合题目条件。 2.以这些起始数为基底,扩展出不符合的数,将其删除就可以。 3.也就是说拓展出的这些数就是题目所不要的对立面的数。
如我们用无平方因子的数,拓展有平方因子的数。
4.用数学归纳法证明一片,看是否有错。 所以我们可以枚举数p的倍数,2 *p*p.....k *p *p,
在进一步这些无平方因子的数必是素数,所以我们可以以素数为基底,拓展有平方因子的数。

40:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<iostream>
#define LL long long
using namespace std;
template<typename T>
inline void read(T &a){
    a=0;bool b=0;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    }
    if(b)a=-a;
}
char C[50];
int temp;
template<typename T>
inline void write(T a){
    if(a<0){
        a=-a;
        putchar('-');
    }
    do{
        C[++temp]=a%10+'0';
        a/=10;
    }
    while(a);
    while(temp)putchar(C[temp--]);
}
LL n,m;
const int maxn=1e7+5;
bool flag[maxn],isprime[maxn/10];
int cnt,prime[maxn/10];
int main(){
    read(n);read(m);
    int end=sqrt(m);
    
    for(int i=2;i<=end;i++){
        if(isprime[i])continue;
        
        for(int j=i*i;j>0&&j<=end;j+=i)isprime[j]=1;
        
        LL j=i*i;
        for(LL k=n;k<n+j&&k<=m;k++){
            if(k%j==0){
                for(LL p=k;p<=m;p+=j){
                    if(!flag[p-n])flag[p-n]=1,cnt++;
                }
                break;
            }
        }
    }
    write(m-n+1-cnt);
    return 0;
}

70:?

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<iostream>
#define LL long long
using namespace std;
template<typename T>
inline void read(T &a){
    a=0;bool b=0;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    }
    if(b)a=-a;
}
char C[50];
int temp;
template<typename T>
inline void write(T a){
    if(a<0){
        a=-a;
        putchar('-');
    }
    do{
        C[++temp]=a%10+'0';
        a/=10;
    }
    while(a);
    while(temp)putchar(C[temp--]);
}
LL n,m;
const int maxn=1e7+5;
bool flag[maxn],isprime[maxn/10];
int cnt;
int main(){
    read(n);read(m);
    int end=sqrt(m);
    
    for(int i=2;i<=end;i++){
        if(isprime[i])continue;//判断在2~sqrt(m)之内的所有prime
        
        for(int j=i*i;j>0&&j<=end;j+=i)isprime[j]=1;//第一次进入for可能会越界
        
        LL j=i*i;//注意int*int=int。。。(无数次错误。。。)
        for(LL k=n/j*j;k<=m;k+=j){
            if(k>=n){
                if(!flag[k-n])flag[k-n]=1,cnt++;
            }
        }
    }
    write(m-n+1-cnt);
    return 0;
}

ac:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<iostream>
#define LL long long
using namespace std;
template<typename T>
inline void read(T &a){
    a=0;bool b=0;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    }
    if(b)a=-a;
}
char C[50];
int temp;
template<typename T>
inline void write(T a){
    if(a<0){
        a=-a;
        putchar('-');
    }
    do{
        C[++temp]=a%10+'0';
        a/=10;
    }
    while(a);
    while(temp)putchar(C[temp--]);
}
LL n,m;
const int maxn=1e7+5;
bool flag[maxn],isprime[maxn];
int cnt;
int main(){
    read(n);read(m);
    int end=sqrt(m);
    
    for(LL i=2;i<=end;i++){
        if(isprime[i])continue;
        
        LL j=i*i;//数据类型??? 
        while(j<=end){//for的智障型错误 
            isprime[j]=1;
            j+=i;
        }
        j=i*i;
        for(LL k=n/j*j;k<=m;k+=j){
            if(k>=n){
                if(!flag[k-n]){
                flag[k-n]=1;
                cnt++;
                } 
            }
        }
    }
    write(m-n+1-cnt);
    return 0;
}

#262. 大于公约数的数

问题描述

给定正整数N,M求gcd(i,N)>=M的i的个数。(1<=i<=N )

输入文件

第一行一个整数T(<=100) 代表测试数据的组数。接下来T行,每行一组测试数据,每组数据两个数字N和M(2<=N<=1000000000, 1<=M<=N)。

输出文件

T行,每组测试数据输出一个数字

样例输入

3
1 1
10 2
10000 72

样例输出

1
6
260

限制与约定

时间限制:1s

空间限制:128MB

好题,gcd(i,n)>=m,i属于【1,n】
暴力时间复杂度过高,我们想怎么才能快速的求出符合条件的解,
我们发现,m实际上是一个没有实际意义的数,m+1 or m-1可能会得到一样的答案
我们逆向思考,如果我们知道了符合条件的d,那么有多少个i呢
这显然可以得到gcd(i/d,n/d)=1,也就是说,当d>=m时,n/d的eular函数值
就是符合条件的解,
那我们证明存在性和唯一性
证:
存在性:
存在一个数i s.t. gcd(i,n)>=m那么根据算法一定会找到这个数
证毕,
证:
唯一性:
设有一个数i s.t. gcd(i,n)>=m但是 会被统计>=2次
根据算法,我们是在(i,n)==1时统计的 i,所以,假设会被统计>=2次
就会有>=2 个符合条件的 d ,与(i,n)有且只有一个矛盾、
证毕
所以算法如下:
枚举n的因子,找到>=m,令其为d,加和 phi(n/d)

与gcd有关的统计问题,考虑eular函数

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define LL long long
using namespace std;
template<typename T >
inline void read(T &a){
    a=0;bool b=0;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    } 
    if(b)a=-a;
}
char C[50];
int temp;
template<typename T>
inline void write(T a){
    if(a<0){
        putchar('-');
        a=-a;
    }
    do{
        C[++temp]=a%10+'0';
        a/=10;
    }while(a);
    while(temp)putchar(C[temp--]);
}
/*inline void Eular(int n){
    for(int i=2;i<=n;i++){
        if(!ip[i]){
        pr[cnt++]=i;
        
        write(i);
        putchar(',');
        }
        for(int j=1;j<=cnt;j++){
            LL t=pr[j]*i;
            if(t>n)break;
            ip[t]=1;
            
            if(i%pr[j]==0)break;
        }
    }
}*/
inline int phi(int n){
    int ans=n,num=n,i=2;
    while(num!=1 && i*i<=n){
        if(num%i==0){
            ans=ans/i*(i-1);
            while(num%i==0)num/=i; 
        }
        i++;
    }
    if(num!=1)ans=ans/num*(num-1);
    return ans;
}
const int maxn=1000000;
int t,n,m;
int main(){
    //freopen("1.out","w",stdout);
    read(t);
    
    while(t--){
        read(n);read(m);
        int i=1,ans=0;
        while(i*i<=n){
            if(n%i==0){
if(i*i==n)ans+=( i>=m ? phi(i) : 0 );
else ans+=( i>=m ?    phi(n/i) : 0)+( (n/i)>=m ? phi(i) : 0 );
            }
            i++;
        }
        write(ans);putchar('\n');
    }
    return 0;
}

272. Gcd(BZOJ2818)

题目描述

给定整数N,求1<=x,y<=N且x,y的最大公约数为素数的数对(x,y)有多少对。

输入文件

一个整数N

输出文件

如题

样例输入

4

样例输出

4

限制与约定

对于10%的数据,N<=10^3

对于20%的数据,N<=10^4

对于40%的数据,N<=10^5

对于60%的数据,N<=10^6

对于100%的数据, N<=10^7

时间限制:1000ms

空间限制:128MB

分析题目,
和gcd有关的统计问题,首先想到Eular函数,
那我们怎么使用呢?
求出1~n内gcd=p的数对个数
我们发现
筛法可以求出所有素数,所以我们枚举每一个素数,考虑1~n内所有可能符合条件的解,
一共有(n/p)个,我们可以用Eular了,求出这(n/p)个数的phi值并相加,就会得到
(x,y)=p & x>y 的数对个数,然后反过来 容斥,就能得到,gcd(x,y)=p的
解的个数
时间复杂度O(n)可以接受
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<cstring>
#define LL long long
using namespace std;
template<typename T>
inline void read(T &a){
    a=0;bool b=0;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    } 
    if(b)a=-a;
}
char C[50];
int temp;
template<typename T>
inline void write(T a){
    if(a<0){
        putchar('-');
        a=-a;
    }
    do{
        C[++temp]=a%10+'0';
        a/=10;
    }while(a);
    while(temp)putchar(C[temp--]);
}
const int maxn=1e7+5;
int phi[maxn],pr[maxn],cnt;
LL sumphi[maxn];
inline void Eular(int n){
    for(int i=1;i<=n;i++)phi[i]=i;sumphi[1]=1ll;
    
    for(int i=2;i<=n;i++){
        if(phi[i]==i){
            phi[i]=i-1;
            pr[++cnt]=i;
        }
        for(int j=1;j<=cnt;j++){
            LL t=pr[j]*i;
            if(t>n)break;
            
            if(i%pr[j]==0){
                phi[t]=phi[i]*pr[j];
                break;
            }
            else{
                phi[t]=phi[i]*(pr[j]-1);
            }
        }
        sumphi[i]=sumphi[i-1]+phi[i];
    }
}
int n;
LL ans;
int main(){

    read(n);
    Eular(n);
    for(int j=1;j<=cnt;j++){
        ans+=(sumphi[ n / pr[j] ]<<1)-1;//去重,(p,p)= p,会重复计算2遍
    }
    write(ans);
    return 0;
}

260. 无关的元素

题目描述

对于给定的n个数a1,a2,...,an,依次求出相邻两数之和,将得到一个新数列。重复上述操作,最后结果将变成一个数。问这个数除以m的余数与哪些数无关?

例如n=3,m=2时,第一次求和得到a1+a2,a2+a3,再次求和得到a1+2a2+a3,它除以2的余数和a2无关。

输入文件

第1行:2个整数n和m(1<=n<=10^5, 2 <=m<=10^9)

输出文件

按升序列出与m无关的元素的序号,每行1个。 若与全部元素无关,输出0

样例输入

5 3

样例输出

3

限制与约定

时间限制:1s

空间限制:128MB

WA:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<iostream>
#define LL long long
using namespace std;
template<typename T>
inline void read(T &a){
    a=0;bool b=0;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=1;
        x=getchar();
    }
    while('0'<=x&&x<='9'){
        a=(a<<1)+(a<<3)+x-'0';
        x=getchar();
    }
    if(b)a=-a;
}
char C[50];
int temp;
template<typename T>
inline void write(T a){
    if(a<0){
        a=-a;
        putchar('-');
    }
    do{
        C[++temp]=a%10+'0';
        a/=10;
    }
    while(a);
    while(temp)putchar(C[temp--]);
}
const int maxn=1e5+5;
int prime[maxn],p;
bool isprime[maxn];

inline void Euler(int n){
    for(int i=2;i<=n;i++){
        if(!isprime[i])prime[++p]=i;
        for(int j=1;j<=p;j++){
            LL t=(LL)prime[j]*i;
            if(t>n)break;
            isprime[t]=1;
            if(i%prime[j]);else break;
        }
    }
}
/*inline void print(){
    for(int i=1;i<=p;i++){
        printf("%d:%d ",prime[i],factor[prime[i]]);
    }
}*/
int n,m,cnt,factor[maxn];//cnt分母有几种质数 
inline void add_factor(int num){
    int i=1;
    int k=num;
    while(prime[i]*prime[i]<=num && k!=1){
        while(!(k%prime[i])){
            k/=prime[i];
            factor[prime[i]]++;
            if(!factor[prime[i]])cnt--;
        }
        i++;
    }
    if(k!=1){
    factor[k]++;
    if(!factor[k])cnt--;
    }
    
}
inline void del_factor(int num){
    int i=1;
    int k=num;
    while(prime[i]*prime[i]<=num && k!=1){
        while(!(k%prime[i])){
            k/=prime[i];
            factor[prime[i]]--;
            if(factor[prime[i]]==-1)cnt++;
        }
        i++;
    }
    if(k!=1){
        if(k>n){
            write(0);
            exit(0);
        }
        else{
        factor[k]--;
        if(factor[k]==-1)cnt++;
        }
    }
}
int main()
{
    read(n);read(m);
    n--;
    Euler(n);
    del_factor(m);
    for(int i=0;i<=n;i++){
        if(cnt<=0){
        write(i+1);
        putchar('\n');
        }
        if(i<n){
        add_factor(n-i);
        del_factor(i+1);
        }
    }
    return 0;
}
posted @ 2019-06-23 15:17  Tj1  阅读(230)  评论(0编辑  收藏  举报