codeforces 822 D. My pretty girl Noora(dp+素数筛)

题目链接:http://codeforces.com/contest/822/problem/D

 

题解:做这题首先要推倒一下f(x)假设第各个阶段分成d1,d2,d3...di组取任意一组来说,如果第i组有n个人参加分成di组那么所需要的为(n/di)*(di*(di-1)/2)=n*(di-1)/2

显然di还可以再分成两阶段di=a*b那么这样的价值就是(n/a)*(a*(a-1)/2)+((n/a)/b)*(b*(b-1)/2)=n*(a-1)/2+n*(b-1)/2a。其实还可以再分那么就要知道分到什么程度就是最小了n*(a-1)/2+n*(b-1)/2a<=n*(a-1)/2+n*(b-1)/2=n*(a+b-2)/2<=n*(a*b-1)/2=n*(di-1)/2也就是说它是越分越小的所以只有当di是素数的时候才是最小的,那么就简单了具体看一下代码。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define mod 1000000007
using namespace std;
typedef long long ll;
const int M = 5e6 + 10;
const ll inf = 1000000000;
const int maxn = 5000500;
int isPrime[maxn];
ll dp[M];
int prime[M];
void IsPrime(){
    prime[2] = 2;
    for(int i = 2 ; i < M ; i++)
        prime[i] = i;
    for(int i = 2 ; i * i < M ; i++)
        if(prime[i] == i)
            for(int j = i * i ; j < M ; j += i)
                prime[j] = min(i , prime[j]);
}//利用素数筛求出每个数最小的素因子。

int main() {
    int t , l , r;
    scanf("%d%d%d" , &t , &l , &r);
    IsPrime();
    dp[1] = 0;
    for(int i = 2 ; i <= r ; i++) {
        dp[i] = inf * inf;
        for(int j = i ; j != 1 ; j /= prime[j]) {
            dp[i] = min(dp[i] , dp[i / prime[j]] + (ll)i * (prime[j] - 1) / 2);
        }//利用公式n*(di-1)/2求值用来更新dp
    }
    ll ans = 0 , cnt = 1;
    for(int i = l ; i <= r ; i++) {
        dp[i] %= mod;
        ans += dp[i] * cnt;
        cnt *= t;
        cnt %= mod;
        ans %= mod;
    }
    printf("%lld\n" , (ans + mod) % mod);
    return 0;
}
posted @ 2017-07-04 09:46  Gealo  阅读(231)  评论(0编辑  收藏  举报