早上看了前三道题目。
第一个是纯暴力,一眼看出来了,Question for the Leader是一个结论题,对于一棵树,如果可以把这棵树分成大小都为k的n/k份,那子树大小是k的倍数的节点恰好有n/k个。(任意选定一个根),这个结论叙述的并不是很好,所以就花了一段时间,第三个则是一个状压dp,由于不会状压dp,就去专门看了一下,但是还没入门就开始了下午的比赛。
下午总共出了四道题目,两道水题,一道优先队列的贪心,一个模拟。然后就一直在搞那个规律题,规律与最后直播讲的大致相同,但是二分被卡了常数,但是因为讲题人没用这种方法写,所以并不知道这样是不是真的对,但赛后改了常数仍然tle,可能是我的二分出现了跳不出来的状况,这也是我的二分恐惧症,但是已经很接近真相了,纪念一下,明天争取肝出来这个题目:
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define mo 1000000007
using namespace std;
long long a[1010],sum[1010];
long long getnum(long long n){
long long num=0;
long long nn=n;
while (nn){
num+=nn/2;
nn=nn/2;
}
return num+n+1;
}
long long qpow(long long a,long long b){
long long ans=1;
long long k=a;
while(b){
if(b&1)ans=ans*k%mo;
k=k*k%mo;
b>>=1;
}
return (ans+mo)%mo;
}
long long getb(long long x){
return (x%mo+(((x%mo)*((x-1)%mo))*qpow(2,mo-2)%mo)+mo)%mo;
}
long long getans(long long n){
long long ans=0;
long long temp=1;
long long fun=2;
while (n){
ans=(ans+(temp%mo)*(getb(n)%mo))%mo;
n/=fun;
temp*=2;
}
return (ans+1+mo)%mo;
}
long long solve(long long n){
long long l=1,r=n;
long long fun;
while (l<=r){
long long mid=(l+r)/2;
if (getnum(mid)<=n){
if (getnum(mid+1))>n){
fun=mid;
break;
}
else {
l=mid;
}
}
else {
r=mid;
}
}
long long ans;
long long fuck=getnum(mid);
ans=(getans(mid)+(((n-fuck)%mo)*((mid+1)%mo))%mo+mo)%mo;
return ans;
}
int main(){
long long i,j,t;
long long n;
a[1]=1;
a[2]=1;
sum[1]=1;
sum[2]=2;
for(i=3;i<=1000;i++){
long long k1=i-a[i-1];
long long k2=i-1-a[i-2];
a[i]=(a[k1]+a[k2])%mo;
sum[i]=(sum[i-1]+a[i])%mo;
}
scanf("%lld",&t);
while (t--){
scanf("%lld",&n);
if (n<=1000){
printf("%lld\n",sum[n]);
}
else {
printf("%lld\n",solve(n));
}
}
}