• 10.13 上午 考试


    T1

    直接二分就好了

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    #include <cstdlib>
    #include <algorithm>
    #define ll long long
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    
    ll n;
    int a,b,d;
    
    ll check(ll x)
    {
        ll t1,t2;
        t1=(ll)(x-a-1)/d+1;
        if(x>b)
            t2=(ll)(x-b-1)/d+1;
        else
            t2=(ll)(b-x-1)/d+1;
        return t1+t2;
    }
    
    ll work1()
    {
        ll ans=max(a,b),l=max(a,b),r=((ll)1<<60),mid,temp;
        while(l<=r)
        {
            mid=(l+r)>>1;
            temp=check(mid);
            if(temp<=n&&ans<mid)
                ans=mid;
            if(l>=r)
                break;
            if(temp<=n)
                l=mid+1;
            else
                r=mid-1;
        }
        return ans;
    }
    
    int main(){
        
        //freopen("T1.in","r",stdin);
    
        scanf("%lld%d%d%d",&n,&d,&a,&b);
        --n;
        cout<<work1();
    }
    T1

    T2

    预处理出来每个点

    $L_i$ i左边第一个比它大的点的位置

    $R_i$ i右边第一个大于等于它的位置(这样是为了统计的时候不重复)

    那么K==$a_i$的区间个数就是$$sum_{a_i==K}(i-L_i)(R_i-i)$$

    然后求一下前缀和和后缀和就行了

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    #include <cstdlib>
    #include <algorithm>
    #define ll long long
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    inline int read()
    {
        char q=getchar();int ans=0;
        while(q<'0'||q>'9')q=getchar();
        while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
        return ans;
    }
    inline char readchar()
    {
        char q=getchar();
        while(q!='<'&&q!='>'&&q!='=')q=getchar();
        return q;
    }
    const int N=100006;
    
    struct JI
    {
        int ff,pos,val;
        bool friend operator < (JI a,JI b)
        {
            return a.val<b.val;
        }
    }ji[N*3];
    int ccc;
    
    int now;
    int n,Q;
    int a[N],K[N];
    char op[N];
    
    void lisan()
    {
        now=0;
        sort(ji+1,ji+1+ccc);
        for(int i=1;i<=ccc;++i)
        {
            if(ji[i].val!=ji[i-1].val)
                ++now;
            if(ji[i].ff==1)
                a[ji[i].pos]=now;
            else
                K[ji[i].pos]=now;
        }
    }
    
    int L[N],R[N];
    
    ll num[N*3],presum[N*3],behsum[N*3];
    
    int zhan[N*2],he;
    void work()
    {
        a[0]=a[n+1]=0x7fffffff;
        he=0;zhan[++he]=0;
        for(int i=1;i<=n;++i)
        {
            while(a[zhan[he]]<=a[i])--he;
            L[i]=zhan[he];
            zhan[++he]=i;
        }
        he=0;zhan[++he]=n+1;
        for(int i=n;i>=1;--i)
        {
            while(a[zhan[he]]<a[i])--he;
            R[i]=zhan[he];
            zhan[++he]=i;
        }
        for(int i=1;i<=n;++i)
            num[a[i]]+=(ll)(i-L[i])*(R[i]-i);
        for(int i=1;i<=now;++i)
            presum[i]=presum[i-1]+num[i];
        for(int i=now;i>=1;--i)
            behsum[i]=behsum[i+1]+num[i];
    
        for(int i=1;i<=Q;++i)
        {
            if(op[i]=='=')
                printf("%lld
    ",num[K[i]]);
            else
                if(op[i]=='<')
                    printf("%lld
    ",presum[K[i]-1]);
            else
                printf("%lld
    ",behsum[K[i]+1]);
        }
    }
    
    int main(){
    
        freopen("T2.in","r",stdin);
    
        n=read();Q=read();
        for(int i=1;i<=n;++i)
        {
            ++ccc;
            ji[ccc].val=read();
            ji[ccc].ff=1;
            ji[ccc].pos=i;
        }
        for(int i=1;i<=Q;++i)
        {
            op[i]=readchar();
            ++ccc;
            ji[ccc].ff=2;
            ji[ccc].val=read();
            ji[ccc].pos=i;
        }
        lisan();
        work();
    }
    T2

    T3

    $f_i$ 所有排列长度为 i 排完序所需要的总步数

    那么 $$f_i=i*f_{i-1}+(2^{i-1}-1)*fac_{i-1}$$

    我们考虑第 i 位都是谁

    是i时,直接加上$f_{i-1}$

    1时,加上$f_{i-1}+2^0*fac_{i-1}$

    ...

    然后求和就可以 $O(n)$ 了

    解释一下转移:

    fac就是阶乘,即长度为 i-1 的排列个数

    每次在长度i-1的后面添加一个数x (当然,前i-1个数里可能有i)

    那把x扔到第x位需要$2^{x-1}$次(i需要0次)

    证明:

    比如 3  1  2 弄成 1 2 3 需要3次

    4  1  2  3 弄成 1 2 4 3 也需要3次

    因为 4可以看成3 再把 3扔到开头到有序,又相当于重复了一遍3  1  2 到  1  2  3 的过程

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    #include <cstdlib>
    #include <algorithm>
    #define ll long long
    #define dd double
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    const int N=100006;
    const int mod=1e9+7;
    
    ll qpow(ll a,int ci)
    {
        ll ans=1;
        while(ci)
        {
            if(ci&1)
                ans=ans*a%mod;
            a=a*a%mod;
            ci>>=1;
        }
        return ans;
    }
    
    ll jie[N],jieni[N];
    void chu()
    {
        jie[0]=1;
        for(int i=1;i<N;++i)
            jie[i]=jie[i-1]*i%mod;
        jieni[N-1]=qpow(jie[N-1],mod-2);
        for(int i=N-2;i>=1;--i)
            jieni[i]=jieni[i+1]*(ll)(i+1)%mod;
        jieni[0]=1;
    }
    
    int n;
    ll f[N],mi[N];
    
    int main(){
    
        chu();
    
        scanf("%d",&n);
        mi[0]=1;
        for(int i=1;i<=n;++i)
        {
            mi[i]=mi[i-1]*2%mod;
            f[i]=f[i-1]*i%mod+(mi[i-1]-1+mod)%mod*jie[i-1]%mod;
        }
        printf("%lld", f[n]%mod*jieni[n]%mod );
    }
    T3

    想不出来也是一种无奈...

  • 相关阅读:
    1.第一个java程序
    5.第三章 运算符和基本选择结构
    7.关系运算符
    4.第二章章末总结
    3.计算员工工资
    JAVA并发操作——Thread常见用法(Sleep,yield,后台线程)
    JAVA 对象序列化(一)——Serializable
    JAVA 线程中的异常捕获
    JAVA反射机制实例
    JAVA 对象序列化(二)——Externalizable
  • 原文地址:https://www.cnblogs.com/A-LEAF/p/7660543.html
Copyright © 2020-2023  润新知