2017-9-22 NOIP模拟赛[xxy][数论]

XXY 的 的 NOIP 模拟赛 4 4 —— 数学专场


A

Description
定义 f(x)表示 x 的约数和,例:f(12)=1+2+3+4+6+12=28
给出 x,y,求Σf(i),i∈[x,y]
Input
一行两个整数 x,y
Output
一行表示答案
Example
两组输入数据
2 4
123 321
对应输出
14
72543
Hint
对于 20%的数据,1<=x<=y<=1000
对于 40%的数据,1<=x<=y<=1e7
对于 100%的数据,1<=x<=y<=2e9

#include<iostream>
#include<cstdio>
using namespace std;
long long x,y;
long long count(int x){
    long long res=0;
    long long l=1,r;
    while(1){
        r=x/(x/l);
        long long a=x/l;
        res+=((l+r)*(r-l+1)/2)*a;
        l=r+1;
        if(x/l==0)break;
    }
    return res;
}
int main(){
    freopen("A.in","r",stdin);
    freopen("A.out","w",stdout);
    cin>>x>>y;
    long long ansl=count(x-1);
    long long ansr=count(y);
    cout<<ansr-ansl;
}
90分 出现整数被0除的错误
#include<iostream>
#include<cstdio>
using namespace std;
long long x,y;
long long count(int x){
    long long res=0;
    long long l=1,r;
    while(1){
        if(x/l==0)r=x;
        else r=x/(x/l);
        long long a=x/l;
        res+=((l+r)*(r-l+1)/2)*a;
        l=r+1;
        if(x/l==0)break;
    }
    return res;
}
int main(){
    freopen("A.in","r",stdin);
    freopen("A.out","w",stdout);
    cin>>x>>y;
    long long ansl=count(x-1);
    long long ansr=count(y);
    cout<<ansr-ansl;
}
100分

 

B

Description
求满足以下条件的 x 的个数
① x∈[1,n!]
② 设 pi 为质数且 pi|x,那么 pi>m,对于所有的 pi 均成立
答案对 100000007 取模
Input
一行两个整数 n,m
Output
一行表示答案
Example
3 组输入样例
100 10
100 20
10000 9000
Output
对应 3 组输出
43274465
70342844
39714141
Hint
对于 20%的数据,n,m<=8
对于 60%的数据,n<=100000,m<=8
对于 100%的数据,n<=10000000,保证 n-m<=100000,m<=n

学到的一点东西

1.x的所有素因子大于m,则x与m!互素
2.已知phi[(i-1)!],递推地求phi[i!]
  如果i是素数,phi[i!]=phi[(i-1)!]*(i-1)
  如果i不是素数,phi[i!]=phi[(i-1)!]*i

3.phi[n!]=phi[m!]*(n!/m!)

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int p[10000],n,m,w=1,ans,cnt;
bool vis[10000000],q[1000000];
void dfs(int pos,long long sum){
    if(sum>w)return;
    if(!q[sum]&&sum!=1)ans++,q[sum]=1;
    //cout<<sum<<' ';
    for(int i=pos;i<=cnt;i++){
        if(sum*p[i]>w)return;
        dfs(i,sum*p[i]);
    }
}
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("B.in","r",stdin);
    freopen("B.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)w*=i;
    for(int i=2;i<=w;i++){
        if(!vis[i])p[++cnt]=i;
        for(int j=1;j<=cnt&&i*p[j]<=w;j++){
            vis[i*p[j]]=1;
            if(i%p[j]==0)break;
        }
    }
    int pos=upper_bound(p+1,p+cnt+1,m)-p;
    dfs(pos,1);
    for(int i=pos;i<=cnt;i++){
        if(cnt>w)break;
        if(!q[p[i]])ans++;
    }
    cout<<ans;
}
20分 暴力
#include<cstdio>
#define N 10000001
#define mod 100000007
using namespace std;
int cnt,p[664580],phi[N];
long long phifac[N];
bool v[N];
int main()
{
    freopen("B.in","r",stdin);
    freopen("B.out","w",stdout);
    phi[1]=1;
    for(int i=2;i<N;i++)
    {
        if(!v[i])
        {
            p[++cnt]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=cnt;j++)
        {
            if(i*p[j]>=N) break;
            v[i*p[j]]=true;
            if(i%p[j]) phi[i*p[j]]=phi[i]*(p[j]-1);
            else
            {
                phi[i*p[j]]=phi[i]*p[j];
                break;
            }
        }
    }
    int n,m; long long ans;
    scanf("%d%d",&n,&m);
        ans=0;
        phifac[1]=1;
        for(int i=2;i<=m;i++) 
        if(!v[i]) phifac[i]=phifac[i-1]*(i-1)%mod;
        else phifac[i]=phifac[i-1]*i%mod;
        ans=phifac[m];
        for(int i=m+1;i<=n;i++) ans=ans*i%mod;
        printf("%I64d\n",ans-1);
}
100分

 

C

Description
令 f(k)=n 表示 有 n 种方式,可以把正整数 k 表示成几个素数的乘积的形式。
例 10=2*5=5*2,所以 f(10)=2
给出 n,求最小的 k
Input
一行一个整数 n
Output
一行表示答案
Example
四组输入样例
1
2
3
105
对应输出:
2
6
12
720
Hint
20%的数据,k<=20
另外 20%的数据,n<=20
另外 20%的数据,k<=1e6
100%的数据,k,n<=2^60

#include<iostream>
#include<cstdio>
using namespace std;
long long a[50];
int k,n,bin[1000],p[100000],cnt;
bool vis[1000000];
bool check(int x){
    int l=0,pos=1;
    while(x!=1){
        while(x%p[pos]!=0)pos++;
        l=l+1;
        bin[l]=0;
        while(x%p[pos]==0){
            bin[l]++;
            x=x/p[pos];
        }
    }
    long long res=1;
    int sum=0;
    for(int i=1;i<=l;i++)sum+=bin[i];
    res=a[sum];
    for(int i=1;i<=l;i++)res/=a[bin[i]];
    if(res==n)return 1;
    return 0;
}
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("C.in","r",stdin);
    freopen("C.out","w",stdout);
    a[1]=1;
    for(int i=2;i<=25;i++)a[i]=a[i-1]*i;
    scanf("%d",&n);
    for(int i=2;i<=100000;i++){
        if(!vis[i])p[++cnt]=i;
        for(int j=1;j<=cnt&&i*p[j]<=100000;j++){
            vis[i*p[j]]=1;
            if(i%p[j]==0)break;
        }
    }
    for(int i=2;i<=100000;i++){//k的所有可能值 
        if(check(i)){
            printf("%d",i);
            return 0;
        }
    }
}
30分 暴力枚举答案
#include<cstdio>
#include<iostream>
using namespace std;
typedef  long long LL;
int p[21]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71};
LL ans,n;
LL C[70][70];
void solve(int num,int lim,LL tot,LL now,int last)
{
    if(now>ans) return;
    if(tot==n) { ans=now; return ; }
    if(tot>n || num>20) return;
    LL t=1;
    for(int i=1;i<=lim;i++)
    {
        t*=p[num];
        if(now>=ans/t) return;
        solve(num+1,i,tot*C[last+i][i],now*t,last+i);
    }
}
int main()
{
    freopen("C.in","r",stdin);
    freopen("C.out","w",stdout);
    C[0][0]=1;
    for(int i=1;i<70;i++)
    {
        C[i][0]=1;
        for(int j=1;j<=i;j++)
            C[i][j]=C[i-1][j-1]+C[i-1][j];
    } 
    scanf("%I64d",&n);
    if(n==1)
    {
           printf("1 2\n");
           return 0;
    }
    ans=(LL)1<<60;
    solve(1,63,1,1,0);
    printf("%I64d\n",ans);
}
100分 搜索+剪枝

 

posted @ 2017-09-22 15:00  Echo宝贝儿  阅读(283)  评论(0编辑  收藏  举报