hdu 6169 DP

传送门

Senior PanⅡ

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 871    Accepted Submission(s): 270


Problem Description

Senior Pan had just failed in his math exam, and he can only prepare to make up for it. So he began a daily task with Master Dong, Dong will give a simple math problem to poor Pan everyday.
But it is still sometimes too hard for Senior Pan, so he has to ask you for help.
Dong will give Pan three integers L,R,K every time, consider all the positive integers in the interval [L,R], you’re required to calculate the sum of such integers in the interval that their smallest divisor (other than 1) is K.

 

Input
The first line contains one integer T, represents the number of Test Cases.
Then T lines, each contains three integers L,R,K(1≤L≤R≤10^11,2≤K≤10^11)
 

Output
For every Test Case, output one integer: the answer mod 10^9+7
 

Sample Input
  
  
2 1 20 5 2 6 3
 

Sample Output
  
  
Case #1: 5 Case #2: 3
 

Source
 

Recommend
liuyiding
 

首先需要检测是否K为质数,因为的范围比较大。K较小时,直接查询数组,当K较大时直接丢miller rabin即可.

然后就是,如何快速求和的问题。

每次都暴力容斥肯定,会超时,因为容斥时有大量重复状态,因为数约除越小,很容易相等。这里考虑动态规划。

现在先来分区间[1,n]容斥后满后足要求【数的数量】的情况,这些【数的和】之后在分析。

1.dp(n,j) 代表前j个质数对,区间[1,n]筛掉前j个质数的倍数后的剩余[数的数量]

2.f(n,j) 代表[1,n]内最小质因数为pri[j]的[数的数量]

 





//china no.1
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <vector>
#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <cstring>
#include <queue>
#include <list>
#include <stdio.h>
#include <set>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <cctype>
#include <sstream>
#include <functional>
#include <stdlib.h>
#include <time.h>
#include <bitset>
using namespace std;

#define pi acos(-1)
#define s_1(x) scanf("%d",&x)
#define s_2(x,y) scanf("%d%d",&x,&y)
#define s_3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define PI acos(-1)
#define endl '\n'
#define srand() srand(time(0));
#define me(x,y) memset(x,y,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
#define close() ios::sync_with_stdio(0); cin.tie(0);
#define FOR(x,n,i) for(int i=x;i<=n;i++)
#define FOr(x,n,i) for(int i=x;i<n;i++)
#define fOR(n,x,i) for(int i=n;i>=x;i--)
#define fOr(n,x,i) for(int i=n;i>x;i--)
#define W while
#define sgn(x) ((x) < 0 ? -1 : (x) > 0)
#define bug printf("***********\n");
#define db double
#define ll long long
#define mp make_pair
#define pb push_back
typedef pair<long long int,long long int> ii;
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL LINF=0x3f3f3f3f3f3f3f3fLL;
const int dx[]={-1,0,1,0,1,-1,-1,1};
const int dy[]={0,1,0,-1,-1,1,-1,1};
const int maxn=1e3+10;
const int maxx=1100310;
const double EPS=1e-8;
const double eps=1e-8;
const LL mod=1e9+7;
template<class T>inline T min(T a,T b,T c) { return min(min(a,b),c);}
template<class T>inline T max(T a,T b,T c) { return max(max(a,b),c);}
template<class T>inline T min(T a,T b,T c,T d) { return min(min(a,b),min(c,d));}
template<class T>inline T max(T a,T b,T c,T d) { return max(max(a,b),max(c,d));}
template <class T>
inline bool scan_d(T &ret){char c;int sgn;if (c = getchar(), c == EOF){return 0;}
while (c != '-' && (c < '0' || c > '9')){c = getchar();}sgn = (c == '-') ? -1 : 1;ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9'){ret = ret * 10 + (c - '0');}ret *= sgn;return 1;}

inline bool scan_lf(double &num){char in;double Dec=0.1;bool IsN=false,IsD=false;in=getchar();if(in==EOF) return false;
while(in!='-'&&in!='.'&&(in<'0'||in>'9'))in=getchar();if(in=='-'){IsN=true;num=0;}else if(in=='.'){IsD=true;num=0;}
else num=in-'0';if(!IsD){while(in=getchar(),in>='0'&&in<='9'){num*=10;num+=in-'0';}}
if(in!='.'){if(IsN) num=-num;return true;}else{while(in=getchar(),in>='0'&&in<='9'){num+=Dec*(in-'0');Dec*=0.1;}}
if(IsN) num=-num;return true;}

void Out(LL a){if(a < 0) { putchar('-'); a = -a; }if(a >= 10) Out(a / 10);putchar(a % 10 + '0');}
void print(LL a){ Out(a),puts("");}
//freopen( "in.txt" , "r" , stdin );
//freopen( "data.txt" , "w" , stdout );
//cerr << "run time is " << clock() << endl;

bool d[maxx];
int pri[maxx],tot=0;
void init()
{
    d[1]=1;
    for(int i=2;i<maxx;i++)
    {
        if(!d[i])
        {
            pri[tot++]=i;
        }
        for(int j=0;pri[j]*i<maxx;j++)
        {
            d[pri[j]*i]=1;
            if(i%pri[j]==0)///遇到最小素因数退出循环
            {
                break;
            }
        }
    }
}

struct node
{
    LL n;
    int j;
    bool operator <(const node &b)const
    {
        if(n!=b.n)
            return n<b.n;
        return j<b.j;
    }
}p;

map<node,LL>dp;

const int s=10;//Miller-Rabin
inline LL mul_mod(LL a, LL b, LL m)  //O(n^(1/4))
{
    LL c = a*b-(LL)((long double)a*b/m+0.5)*m;
    return c<0 ? c+m : c;
}

LL fast_exp(LL a,LL x,LL m)
{
    LL b = 1;
    while (x)
    {
        if (x & 1)
            b = mul_mod(b, a, m);
        a = mul_mod(a, a, m);
        x >>= 1;
    }
    return b;
}

bool MR(LL n)
{
    if (!(n&1))
        return n == 2;
    LL t = 0, u;
    for (u = n-1; !(u&1); u >>= 1)
        ++t;
    for (int i = 0; i < s; ++i)
    {
        LL a = rand()%(n-2)+2, x = fast_exp(a, u, n);
        for (LL j = 0, y; x != 1 && j < t; ++j, x = y)
        {
            y = mul_mod(x, x, n);
            if (y == 1 && x != n-1)
                return false;
        }
        if (x != 1)
            return false;
    }
    return true;
}

LL dfs(LL n,int j)
{
    if(n<=0)
        return 0;
    if(j<0)
    {
        if(n&1)
        {
            return (n+1)/2%mod*(n%mod)%mod;
        }
        return n/2%mod*((n+1)%mod)%mod;
    }
    node t;
    t.n=n;
    t.j=j;
    if(dp.count(t)<1)
    {
        dp[t]=(dfs(n,j-1)-1ll*pri[j]*dfs(n/pri[j],j-1))%mod;
    }
    return dp[t]%mod;

}
LL calc(LL n,LL k)
{
    if(k>n)
    {
        return 0;
    }
    else if(n/k<k)
    {
        return k%mod;
    }
    else
    {
        int m=lower_bound(pri,pri+tot,k)-pri;
        return dfs(n/k,m-1)%mod*k%mod;///答案是f(n,m-1)=dfs(n/k,m-1)*k
    }

}
int t,cas=1;
LL L,R,K;
int main()
{
    //freopen( "in.txt" , "r" , stdin );
    init();
    scan_d(t);
    W(t--)
    {
        dp.clear();
        scan_d(L),scan_d(R),scan_d(K);
        LL ans=0;
        if(MR(K))
        {
            ans=calc(R,K)-calc(L-1,K);
            ans=(ans%mod+mod)%mod;
        }
        printf("Case #%d: %I64d\n",cas++,ans);
    }
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值