1. 程式人生 > >10.13 上午 考試

10.13 上午 考試

san 區間 mic 大於等於 mil ons spa ios 技術

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

想不出來也是一種無奈...

10.13 上午 考試