牛客挑战赛-54 B

题目

题意: 求[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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值