1. 程式人生 > >2018年7月23日暑假訓練日記

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));
        }
    }
}