题意: 求[l,r]的 k次根号下i (向下取整) 之和. k<=20, l,r <= 1e18
思路:
①k=1,即求[l,r]之和。
②k >= 3,预处理出x的k次方,时间复杂度最多 三次根号1e18 = 1e6,可过。
[x^k, (x+1)^k),开k次根号以后都是x.由此可以用前缀和维护出1 - x^k的累积贡献. 求出最大的满足x ^ k <= l的x,可以用当前x^k对应的前缀和 + 后边一部分的贡献,求得答案。
③k = 2,不能暴力预处理了。考虑到1,4,9,16.每两个平方数之间数的个数为3,5,7,而且对应贡献为1,2,3.也就是 (2*i+1)i.当我们求出最大的满足x ^ 2 <= l的x后,可以通过通项公式求和S求出累积贡献,再加上后边的贡献即可。S = 2前n项平方和 + n项和。
k=2时用二分找的x^2 <= l,后来看了别的孩子题解发现不知道在干什么,我直接sqrt开根号不就行了。。。
代码:
// Problem: 小䓤的一些数字
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11194/B
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<complex>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<unordered_map>
#include<list>
#include<set>
#include<queue>
#include<stack>
#define OldTomato ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define fir(i,a,b) for(int i=a;i<=b;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define p_ priority_queue
// round() 四舍五入 ceil() 向上取整 floor() 向下取整
// lower_bound(a.begin(),a.end(),tmp,greater<ll>()) 第一个小于等于的
// #define int long long //QAQ
using namespace std;
typedef complex<double> CP;
typedef pair<int,int> PII;
typedef long long ll;
// typedef __int128 it;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll inf = 1e18;
const int N = 2e5+10;
const int M = 1e6+10;
const int mod = 1e9+7;
const double eps = 1e-6;
inline int lowbit(int x){ return x&(-x);}
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
#define int __int128
int n,m,k,T;
int l,r;
int f1(int n) //前n项和
{
return n*(n+1)*(2*n+1)/6;
}
int f2(int n)
{
return n*(n+1)/2;
}
int qpow(int a,int k)
{
int res = 1;
while(k)
{
if(k&1) res = res * a ;
a = a * a;
k >>= 1;
}
return res;
}
int a[M];
int s[M];
void solve()
{
read(l); read(r);
read(k);
if(k!=1) l -- ;
int ans = 0;
if(k == 1)
{
ans += (r-l+1) * (l+r)/2;
}
else if(k == 2)
{
int idx1 = sqrt((ll)l);
int idx2 = sqrt((ll)r);
int res1 = 2 * f1(idx1-1) + f2(idx1-1);
int res2 = 2 * f1(idx2-1) + f2(idx2-1);
res1 += (l - qpow(idx1,k) + 1) * (idx1);
res2 += (r - qpow(idx2,k) + 1) * (idx2);
ans = res2 - res1;
}
else
{
int i = 1;
for(i=1;;++i)
{
a[i] = qpow(i,k);
if(a[i] > r) break;
s[i] = s[i-1] + (a[i] - a[i-1]) * (i-1) + 1;
}
n = i-1;
int idx1 = lower_bound(a+1,a+n+1,l) - a;
idx1 -- ;
int idx2 = lower_bound(a+1,a+n+1,r) - a;
idx2 -- ;
int res1 = s[idx1];
int res2 = s[idx2];
res1 += (l - a[idx1]) * (idx1);
res2 += (r - a[idx2]) * (idx2);
ans = res2 - res1;
}
write(ans);
}
signed main(void)
{
T = 1;
// OldTomato; cin>>T;
// read(T);
while(T--)
{
solve();
}
return 0;
}