题目描述
做
容易归纳出Si就是i在k进制数下各数位上的数的和再模k。
证明很简单。
我们只需要维护k进制分解即可。
用一个数组维护,每次把最低位+1,然后考虑进位。
均摊分析这是线性的:
设势函数为k-1的数量。
每次若进位了s个,那么势函数减少了s,并可能增加1,实际消耗时间为s+1,因此Ai<=s+1-s+1=2
均摊复杂度为O(1)
优化常数使用模优化即可
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll mo=4294967296;
const int a=20000116,b=804,c=233;
ll s[70];
ll i,j,k,l,r,h,m,t,ans,ca,top;
ll read(){
ll x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
int main(){
freopen("fantasy.in","r",stdin);freopen("fantasy.out","w",stdout);
ca=read();
while (ca--){
k=read();l=read();r=read();
//l--;r--;
top=t=0;
j=l;
while (j){
s[top]=j%k;
t+=s[top];
if (t>=k) t-=k;
j/=k;
top++;
}
m=l%a;
h=(m*m+l+b)/c;
//printf("%d\n",h);
ans=h*t%mo;
fo(i,l+1,r){
s[0]++;t++;
if (t>=k) t-=k;
j=0;
while (s[j]==k){
//t-=k;
s[j]=0;
s[++j]++;
t++;
if (t>=k) t-=k;
}
m++;
if (m==a) m=0;
h=(m*m+i+b)/c;
//printf("%d\n",h);
ans=ans+h*t%mo;
if (ans>=mo) ans-=mo;
}
printf("%lld\n",ans);
fo(i,0,65) s[i]=0;
}
}