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\n",num[K[i]]);
        else
            if(op[i]=='<')
                printf("%lld\n",presum[K[i]-1]);
        else
            printf("%lld\n",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

 

 

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

 

posted @ 2017-10-13 12:12  A_LEAF  阅读(127)  评论(0编辑  收藏  举报