1.13 考试总结

T1 [TJOI2019] 甲苯先生的滚榜

题目链接

平衡树裸题,随便一种平衡树应该都可以.但是要注意常数问题,不要以为 \(10s\) 的时限很松...

#include <cstdio>
#include <cstring>
typedef long long ll;
typedef unsigned int ui;
inline int rd(){
    int x=0,p=1;
    char a=getchar();
    while((a<48||a>57)&&a!='-')a=getchar();
    if(a=='-')p=-p,a=getchar();
    while(a>47&&a<58)x=(x<<1)+(x<<3)+(a&15),a=getchar();
    return x*p;
}
inline ui randNum(ui &seed, ui last,const ui m){
    seed=seed*17+last;
    return seed%m+1;
}
const int N=100002;
ui seed,lst=7;
int T,n,q;
int root,Size,ft[N],cnt[N],son[N][2],vala[N],valb[N],size[N];
int ac[N],ti[N];
inline void init(){
    memset(ac,0,sizeof ac);
    memset(ti,0,sizeof ti);
    memset(ft,0,sizeof ft);
    memset(son,0,sizeof son);
    memset(cnt,0,sizeof cnt);
    memset(vala,0,sizeof vala);
    memset(valb,0,sizeof valb);
    memset(size,0,sizeof size);
    root=0,Size=0;
}
inline void pushup(int x){
    size[x]=size[son[x][0]]+size[son[x][1]]+cnt[x];
}
inline int get(int x){
    return x==son[ft[x]][1];
}
inline void clear(int x){
    son[x][0]=son[x][1]=ft[x]=cnt[x]=vala[x]=valb[x]=size[x]=0;
}
inline void rotate(int x){
    int f=ft[x],ff=ft[f],d=get(x);
    son[f][d]=son[x][d^1],ft[son[x][d^1]]=f;
    son[x][d^1]=f,ft[ff]=x;
    ft[x]=ff;
    if(ff)son[ff][get(f)]=x;
    pushup(f),pushup(x);
}
inline void splay(int x,int g=0){
    while(ft[x]!=g){
        int f=ft[x],ff=ft[f];
        if(ff!=g) get(x)==get(f)?rotate(f):rotate(x);
        rotate(x);
    }
    if(!g) root=x;
}
inline void insert(int a,int b){
    if(!root){
        vala[++Size]=a,valb[Size]=b;
        root=Size,cnt[Size]++;
        pushup(root);
        return;
    }
    int now=root,f=0;
    while(1){
        if(vala[now]==a&&valb[now]==b){
            cnt[now]++,pushup(now),splay(now);
            break;
        }
        f=now;
        if(a<vala[now]||(a==vala[now]&&b>valb[now])) now=son[now][1];
        else now=son[now][0];
        if(!now){
            vala[++Size]=a,valb[Size]=b;
            cnt[Size]++;
            ft[Size]=f,son[f][a<vala[f]||(a==vala[f]&&b>valb[f])]=Size;
            pushup(f),pushup(Size);
            splay(Size);
            break;
        }
    }
}
inline int rank(int a,int b){
    int ans=0,now=root;
    while(1){
        if(a>vala[now]||(a==vala[now]&&b<valb[now])) now=son[now][0];
        else{
            ans+=size[son[now][0]];
            if(a==vala[now]&&b==valb[now]){
                splay(now);
                return ans+1;
            }
            ans+=cnt[now],now=son[now][1];
        }
    }
}
inline int pre(){
    int now=son[root][0];
    while(son[now][1]) now=son[now][1];
    return now;
}
inline void del(int a,int b){
    rank(a,b);
    if(cnt[root]>1){
        cnt[root]--,pushup(root);
        return;
    }
    if(!son[root][0]&&!son[root][1]){
        clear(root),root=0;
        return;
    }
    if(!son[root][0]){
        int now=root;
        root=son[now][1];
        ft[root]=0;
        clear(now);
        return;
    }
    if(!son[root][1]){
        int now=root;
        root=son[now][0];
        ft[root]=0;
        clear(now);
        return;
    }
    int x=pre(),now=root;
    splay(x);
    ft[son[now][1]]=x;
    son[x][1]=son[now][1];
    clear(now);
    pushup(root);
}
int main(){
    freopen("roll.in","r",stdin);
    freopen("roll.out","w",stdout);
    T=rd();
    while(T--){
        init();
        n=rd(),q=rd(),seed=rd();
        while(q--){
            ui ria=randNum(seed,lst,n);
            ui rib=randNum(seed,lst,n);
            if(ac[ria]) del(ac[ria],ti[ria]);
            ac[ria]++,ti[ria]+=rib;
            insert(ac[ria],ti[ria]);
            lst=rank(ac[ria],ti[ria])-1;
            printf("%d\n",lst);
        }
    }
    return 0;
}

T2 [SDOI2016]排列计数

题目链接

\(f_{i}\)\(n\) 个数任意一个数都不在对应位置上的排列方案数,则答案为 \(\dbinom{n}{m} * f_{n-m}\).

显然 \(f_{1}=0 \ , f_{2}=1\).设 \(n\) 被放在了第 \(k\) 个位置,则若 \(k\) 在第 \(n\) 位,则已确定两个数,相当于 \(f_{n-2}\);当 \(k\) 不在第 \(n\) 位时只能确定一个,相当于 \(f_{n-1}\). 由于 \(k\)\(n-1\) 种取值,所以综合以上公式得到:

\[f_{i}=(n-1)*(f_{i-1}+f_{i-2})\]

再配合组合数和逆元即可求解.

#include <cstdio>
#include <algorithm>
typedef long long ll;
inline int rd(){
    int x=0,p=1;
    char a=getchar();
    while((a<48||a>57)&&a!='-')a=getchar();
    if(a=='-')p=-p,a=getchar();
    while(a>47&&a<58)x=(x<<1)+(x<<3)+(a&15),a=getchar();
    return x*p;
}
const int N=1000002,S=1000000;
const ll mod=1e9+7;
int T,n,m;
ll fac[N],inv[N],f[N];
ll ans=0;
inline ll fpow(ll b,ll p=mod-2){
    ll ans=1,tmp=b;
    while(p){
        if(p&1)ans=ans*tmp%mod;
        tmp=tmp*tmp%mod;
        p>>=1;
    }
    return ans;
}
inline ll C(int n,int m){
    return fac[n]*inv[n-m]%mod*inv[m]%mod;
}
int main(){
    freopen("permutation.in","r",stdin);
    freopen("permutation.in","w",stdout);
    fac[0]=1;
    for(int i=1;i<=S;i++)fac[i]=fac[i-1]*i%mod;
    inv[S]=fpow(fac[S]);
    for(int i=S-1;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
    f[1]=0,f[2]=1;
    for(int i=3;i<=S;i++)f[i]=(i-1)*(f[i-1]+f[i-2])%mod;
    T=rd();
    while(T--){
        n=rd(),m=rd();
        if(n==m)puts("1");
        else printf("%lld\n",C(n,m)*f[n-m]%mod);
    }
    return 0;
}

T3 [CQOI2007]余数求和

题目链接

\[\sum\limits_{i=1}^{n}k \bmod i\]

\[=n*k \ - \sum\limits_{i=1}^n i*\left\lfloor\dfrac{k}{i}\right\rfloor\]

是一个整除分块的形式,可以 \(O(\sqrt{k})\) 求解.

扫描二维码关注公众号,回复: 8625184 查看本文章
#include <cstdio>
typedef long long ll;
inline ll rd(){
    ll x=0,p=1;
    char a=getchar();
    while((a<48||a>57)&&a!='-')a=getchar();
    if(a=='-')p=-p,a=getchar();
    while(a>47&&a<58)x=(x<<1)+(x<<3)+(a&15),a=getchar();
    return x*p;
}
ll n,k;
ll ans=0;
inline ll min(ll x,ll y){return x<y?x:y;}
int main(){
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    n=rd(),k=rd();
    ans=n*k;
    n=min(n,k);
    for(ll l=1,r;l<=n;l=r+1){
        r=min(n,k/(k/l));
        ans-=(k/l)*(r-l+1)*(r+l)/2;
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wsk1202/p/12198675.html