数论题

hdu4704 Sum

题面:

在这里插入图片描述

思路:

一开始没看懂题。。。

其实就是把n拆成若干正整数之和,计算一共有多少种拆法。
而且因为每个X[i]是有编号i的,所以a+b和b+a算两种。

把n看成n个1排在一排,然后放隔板去分割,一共n-1个空位,每个空位有放和不放两种选择,因此总的方案数是2n-1
然后看到n非常大,已经是数字串了,考虑降幂。
因为1e9+7是质数,根据费马小定理,把幂次(n-1)对1e9+6取模即可降幂。
之后就变成一道快速幂简单题了。

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int ppow(int a,int b,int mod){
    a%=mod;
    int ans=1;
    while(b){
        if(b&1)ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
const int maxm=1e5+5;
const int mod=1e9+7;
char s[maxm];
signed main(){
    while(scanf("%s",s+1)!=EOF){
        int n=strlen(s+1);
        int p=0;
        for(int i=1;i<=n;i++){
            p=(p*10+s[i]-'0')%(mod-1);
        }
        p=(p-1+mod-1)%(mod-1);
        cout<<ppow(2,p,mod)<<endl;
    }
    return 0;
}

hdu5750 Dertouzos

题意:

给n和d,问有多少个比n小的正整数,其不等于自身的最大约数为d。

思路:

一开始以为是水题,这不就是统计1-(n-1)中有多少个(d乘prime)吗
然而还是太年轻了,这题还有一个细节:
如果d是prime的倍数,那么就可以把d质因子分解,(d乘prime)可以提出来一个最小的质因子p,(d乘prime)=(p乘dd)
其中dd是新的最大因子,这样就不满足最大因子为d了,所以循环到d%prime==0之后就要跳出去。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
bool notprime[maxm];
int prime[maxm],cnt;
void init(){
    for(int i=2;i<maxm;i++){
        if(!notprime[i]){
            prime[cnt++]=i;
        }
        for(int j=0;j<cnt;j++){
            if(1LL*prime[j]*i>=maxm)break;
            notprime[prime[j]*i]=1;
            if(i%prime[j]==0)break;
        }
    }
}
signed main(){
    init();
    int T;
    cin>>T;
    while(T--){
        int n,d;
        scanf("%d%d",&n,&d);
        int ans=0;
        for(int i=0;i<cnt;i++){
            if(prime[i]>d)break;
            if(1LL*prime[i]*d>=n)break;
            ans++;
            if(d%prime[i]==0)break;//如果能整除d,那么d就可以被分解,形成d'(d'>d)
        }
        printf("%d\n",ans);
    }
    return 0;
}

CodeForces484 B.Maximum Value

题意:

给长度为n的数组a
要求计算a(i)%a(j)的最大值,其中a(i)>=a(j)
数据范围:n<=2e5,a(i)<=1e6

思路:

首先暴力O(n2)枚举肯定超时。

设a(i)%a(j)=x
则x=a(i)-a(j)k,由取余性质可知,a(j)k<=a(i)<=a(j)(k+1)
因为题目数据最大1e6,所以可以直接枚举a(j)和倍数(k+1),在数组中二分出小于a(j)(k+1)的最大的数a(t)
因为显然a(j)k<=a(i)<=a(j)(k+1)范围中的a(i)越大,答案x越大。

如果a(j)(k+1)-a(t)<a(j)说明a(j)k<=a(t)<=a(j)(k+1),即合法,用a(t)%a(j)更新答案。
当a(j)k>1e6的时候停止枚举k。

ps:
因为要二分,所以数组需要先排序
如果数组中由重复的a(j),只计算一次就行了。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e6+5;
int a[maxm];
signed main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    sort(a+1,a+1+n);
    int ans=0;
    for(int j=1;j<=n;j++){//枚举模数a[j];
        if(a[j]==a[j-1])continue;
        for(int k=1;;k++){//枚举倍数
            int now=(k+1)*a[j];
            int l=1,r=n;
            int pos=0;
            while(l<=r){
                int mid=(l+r)/2;
                if(a[mid]<now)pos=mid,l=mid+1;
                else r=mid-1;
            }
            if(!pos)break;
            if(now-a[pos]<a[j]){
                ans=max(ans,a[pos]%a[j]);
            }
            if(now>1e6)break;
        }
    }
    printf("%d\n",ans);
    return 0;
}

CodeForces1247 D. Power Products

题意:

给长度为n的数组a,和一个整数k
问有多少对1<=i<j<=n
满足a(i)*a(j)=xk,其中x为任意数
数据范围:n<=2e5,k<=100,a(i)<=1e5

思路:

两数的乘积是x的k次方,那么他们乘积的每种质因子的幂次都是k的倍数,
用vector+pair记录每个数的质因子以及次数,找出要匹配的质因子以及次数,用map记录和查询即可

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e5+5;
map<vector<pair<int,int> >,int>mark;
int a[maxm];
int n,k;
int ans;
signed main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        vector<pair<int,int> >now;
        vector<pair<int,int> >need;
        for(int j=2;j*j<=a[i];j++){
            if(a[i]%j==0){
                int cnt=0;
                while(a[i]%j==0){
                    a[i]/=j;
                    cnt++;
                }
                cnt%=k;//对k取模
                if(cnt){//如果为0就不用加进去了
                    now.push_back({j,cnt});
                }
            }
        }
        if(a[i]!=1){
            now.push_back({a[i],1});
        }
        for(auto i:now){
            need.push_back({i.first,k-i.second});
        }
        ans+=mark[need];
        mark[now]++;
    }
    cout<<ans<<endl;
    return 0;
}

AtCoder5361(ABC158E) Divisible Substring

题意:

给一个长度为n的数字串和一个质数p
问有多少个子串模p等于0

思路:

当p为2和5的时候,所有10的倍数模p都是0,例如(100a+10b+c)%p等价于c%p,因此只判断最后一位是否模p等于0即可。

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=5e5+5;
map<int,int>mark;
char s[maxm];
int n,p;
signed main(){
    cin>>n>>p;
    scanf("%s",s+1);
    int ans=0;
    if(p==2||p==5){
        for(int i=1;i<=n;i++){
            if((s[i]-'0')%p==0){
                ans+=i;
            }
        }
    }else{
        int base=1;
        int sum=0;
        mark[0]=1;
        for(int i=n;i>=1;i--){
            sum=(sum+(s[i]-'0')*base)%p;
            ans+=mark[sum];
            mark[sum]++;
            base=base*10%p;
        }
    }
    cout<<ans<<endl;
    return 0;
}

发布了430 篇原创文章 · 获赞 36 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/104254932