2018年7月23日暑假訓練日記
早上看了前三道題目。
第一個是純暴力,一眼看出來了,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));
}
}
}