题目链接: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 " , (ans + mod) % mod); return 0; }