NOIP 模擬 七十四


T1 自然數

首先預處理以一為左端點所有的 mex 值,然后插入線段樹中。

考慮如何修改,左端點右移一位,相當於把那一位的數刪掉了,記錄下一個出現這個數的位置為 pos ,那么i 到 pos 之間所有大於 x 的 mex 都要修改為 x。

剩下的就是線段樹基本操作了。

#include<bits/stdc++.h>
#define N 200010
#define int long long
using namespace std;
int n,jie,a[N];
long long ans;
int tree[N<<2],sum[N<<2],minn[N<<2],tag[N<<2],tong[N],ji,c[N],nxt[N],maxn[N<<2];
struct jj 
{int ai,id;}p[N];
inline void pushup(int x)
{   sum[x]=sum[x<<1]+sum[x<<1|1];
    minn[x]=min(minn[x<<1],minn[x<<1|1]);
    maxn[x]=max(maxn[x<<1],maxn[x<<1|1]);
}#include<bits/stdc++.h>
#define N 200010
#define int long long
using namespace std;
int n,jie,a[N];
long long ans;
int tree[N<<2],sum[N<<2],minn[N<<2],tag[N<<2],tong[N],ji,c[N],nxt[N],maxn[N<<2];
struct jj 
{int ai,id;}p[N];
inline void pushup(int x)
{   sum[x]=sum[x<<1]+sum[x<<1|1];
    minn[x]=min(minn[x<<1],minn[x<<1|1]);
    maxn[x]=max(maxn[x<<1],maxn[x<<1|1]);
}
inline void pushdown(int x,int l,int r)
{   minn[x<<1]=minn[x<<1|1]=maxn[x<<1]=maxn[x<<1|1]=tag[x<<1]=tag[x<<1|1]=tag[x];
    int mid=(l+r)>>1;sum[x<<1]=tag[x]*(mid-l+1);sum[x<<1|1]=tag[x]*(r-mid);tag[x]=-1;
}
inline void build(int x,int l,int r)
{   if(l==r){sum[x]=minn[x]=maxn[x]=c[l];return;}
    int mid=(l+r)>>1;
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    pushup(x);
}
inline int query(int x,int l,int r,int L,int R)
{   if(l>=L and r<=R)return sum[x];
    int mid=(l+r)>>1,res=0;if(tag[x]!=-1)pushdown(x,l,r);
    if(mid<R)res+=query(x<<1|1,mid+1,r,L,R);
    if(mid>=L)res+=query(x<<1,l,mid,L,R);
    return res;
}
inline void update(int x,int l,int r,int L,int R,int val)
{   if(L>R)return;
    if(l>=L and r<=R and minn[x]>=val){maxn[x]=minn[x]=val;sum[x]=val*(r-l+1);tag[x]=val;return;}
    int mid=(l+r)>>1;if(tag[x]!=-1)pushdown(x,l,r);
    if(mid<R and maxn[x<<1|1]>val)update(x<<1|1,mid+1,r,L,R,val);
    if(mid>=L and maxn[x<<1]>val)update(x<<1,l,mid,L,R,val);
    pushup(x);
}
signed main()
{   freopen("mex.in","r",stdin);
    freopen("mex.out","w",stdout);
    scanf("%lld",&n);
    for(int i=1;i<=n;++i)scanf("%lld",&a[i]),p[i]=(jj){a[i],i};
    int zhi=0;
    for(int i=1;i<=n;++i)
    {   if(a[i]<=n)tong[a[i]]=1;
        while(tong[zhi])++zhi;
        c[i]=zhi;
    }
    memset(tong,0,sizeof(tong));memset(tag,-1,sizeof(tag));
    for(int i=n;i;--i)if(a[i]<=n){nxt[i]=tong[a[i]];tong[a[i]]=i;} 
    build(1,1,n);
    for(int i=1;i<=n;++i)
    {   ans+=query(1,1,n,i,n);
        if(a[i]<=n)
        {   int pos=nxt[i];
            if(!pos)pos=n+1;
            update(1,1,n,i,pos-1,a[i]);  
        }
    }
    printf("%lld\n",ans);
}
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    pushup(x);
}
inline int query(int x,int l,int r,int L,int R)
{   if(l>=L and r<=R)return sum[x];
    int mid=(l+r)>>1,res=0;if(tag[x]!=-1)pushdown(x,l,r);
    if(mid<R)res+=query(x<<1|1,mid+1,r,L,R);
    if(mid>=L)res+=query(x<<1,l,mid,L,R);
    return res;
}
inline void update(int x,int l,int r,int L,int R,int val)
{   if(L>R)return;
    if(l>=L and r<=R and minn[x]>=val){maxn[x]=minn[x]=val;sum[x]=val*(r-l+1);tag[x]=val;return;}
    int mid=(l+r)>>1;if(tag[x]!=-1)pushdown(x,l,r);
    if(mid<R and maxn[x<<1|1]>val)update(x<<1|1,mid+1,r,L,R,val);
    if(mid>=L and maxn[x<<1]>val)update(x<<1,l,mid,L,R,val);
    pushup(x);
}
signed main()
{   freopen("mex.in","r",stdin);
    freopen("mex.out","w",stdout);
    scanf("%lld",&n);
    for(int i=1;i<=n;++i)scanf("%lld",&a[i]),p[i]=(jj){a[i],i};
    int zhi=0;
    for(int i=1;i<=n;++i)
    {   if(a[i]<=n)tong[a[i]]=1;
        while(tong[zhi])++zhi;
        c[i]=zhi;
    }
    memset(tong,0,sizeof(tong));memset(tag,-1,sizeof(tag));
    for(int i=n;i;--i)if(a[i]<=n){nxt[i]=tong[a[i]];tong[a[i]]=i;} 
    build(1,1,n);
    for(int i=1;i<=n;++i)
    {   ans+=query(1,1,n,i,n);
        if(a[i]<=n)
        {   int pos=nxt[i];
            if(!pos)pos=n+1;
            update(1,1,n,i,pos-1,a[i]);  
        }
    }
    printf("%lld\n",ans);
}

T2 錢倉

貪心,一定存在中轉點,一定存在一個分界點滿足只向一遍運輸,這個分界點就是最大子段和的起點。

#include<bits/stdc++.h>
#define int long long
#define N 200005
using namespace std;
int n,c[N],sum[N],nxt[N],maxn,id,tmp,t[N],ans,old[N];
signed main()
{   freopen("barn.in","r",stdin);
    freopen("barn.out","w",stdout);
    scanf("%lld",&n);
    for(int i=1;i<=n;++i)scanf("%lld",&c[i]);
    for(int i=1;i<=n;++i)
    {   tmp+=c[i];
        if(tmp<i-id)id=i,tmp=0;
    }
    ++id;
    for(int i=id;i<=n;++i)t[i-id+1]=c[i];for(int i=1;i<id;++i)t[i+n-id+1]=c[i];
    int zhi1=n;
    for(int i=n;i;--i)
    {   if(zhi1>i)zhi1=i;
        while(!t[zhi1])--zhi1;
        if(!t[i])ans+=(i-zhi1)*(i-zhi1),--t[zhi1];
    }
    printf("%lld\n",ans);
}

T3 游戲

Alice Bod 都絕頂聰明。因為他們的概率是得到自己想要的一面,而並不是固定的一面。所以我們首先來分析一下他們的策略,也就是他們到底想要干神魔。

  1. 如果本回合 A 想要正面,那么在這一回合結束之前 A 一直想要正面。

  2. 這次結果意味着下一輪的先后順序,那么先手一定選擇對他最有利的局面,也就是獲勝概率最大的一個局面。

  3. 后手會選擇和先手相同的策略,因為他要阻止先手獲勝。

如果只剩下一個子,那么顯然先手要去拿並且先手勝率大,那么兩個子時先手為了保證自己是先手所以不會拿,以此類推。。。。我們得到省偶數個子時都不想拿,省奇數個子時都想拿。

於是我們接下來考慮計算拿到石子的概率,這個東西分八種,分別是誰先手想不想拿誰拿到了。

因為道理相同這里只推一個示例,A 先手,兩人都想拿,A 拿到的概率。

顯然為 \(\sum\limits _{i=0}^{+\infty}p \times ((1-p) \times (1-q))^i\)

設后面的底數為 x。

於是變為 \(p\times \sum\limits_{i=0}^{+\infty}x^i = \dfrac{p}{1-x}\)

接下來設計狀態轉移,設f/g,i,0/1 表示誰先手,還剩幾個子,最后誰贏得概率。

示例 \(f_{i,0}\)為 A 先手,還剩 i 個子,先手勝利的概率。

\(f_{i,0}=\frac{p}{1-(1-p)\times (1-q)}\times g_{i-1,1}+(1-\frac{p}{1-(1-p)\times (1-q)}) \times f_{i-1,0}\)

其他的轉移同理。

接下來考慮優化,我用了倍增。因為奇數偶數轉移系數不同,所以我將一輪奇數偶數看成一個整體,做一半,然后再看最后是否還需要轉移一步。

倍增的話就是把上述方程含義變為還剩下 \(2^i\) 個石子。最后二進制拆分合並。

不得不吐槽,這傻逼題太坑了,我在考場上用腎旰了兩個小時大樣例,結果傻逼樣例是錯的,這TMD算怎么回事,dp 推出來死活不對,最后也沒敢交。。。。。。。。。

#include<bits/stdc++.h>
#define int long long
#define mod 1000000007
using namespace std;
int p,q,n,t,dp1[66][2],dp2[66][2],dp3[66][2],dp4[66][2],xi1[2][2],xi2[2][2],dip1[66][2],dip2[66][2];
int f[2][2];
inline int qpow(int a,int b){int base=1;while(b){if(b&1)base=base*a%mod;a=a*a%mod;b>>=1;}return base;}
signed main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    scanf("%lld",&t);
    while(t--)
    {   scanf("%lld%lld%lld",&n,&p,&q);
        p=p*qpow(100000000,mod-2)%mod;
        q=q*qpow(100000000,mod-2)%mod;
        int base1=(1-p+mod)%mod,base2=(1-q+mod)%mod;
        int ans=p*qpow((1-base1*base2%mconst int JBB=0;od+mod)%mod,mod-2)%mod;
        dp1[0][0]=xi1[0][0]=ans,dp1[0][1]=xi1[0][1]=(1-ans+mod)%mod;
        ans=q*qpow((1-base1*base2%mod+mod)%mod,mod-2)%mod;
        dp2[0][0]=xi1[1][0]=ans,dp2[0][1]=xi1[1][1]=(1-ans+mod)%mod;
        p=(1-p+mod)%mod;q=(1-q+mod)%mod;
        base1=(1-p+mod)%mod,base2=(1-q+mod)%mod;
        ans=p*qpow((1-base1*base2%mod+mod)%mod,mod-2)%mod;
        dp3[0][0]=xi2[0][0]=ans;dp3[0][1]=xi2[0][1]=(1-ans+mod)%mod;
        ans=q*qpow((1-base1*base2%mod+mod)%mod,mod-2)%mod;
        dp4[0][0]=xi2[1][0]=ans;dp4[0][1]=xi2[1][1]=(1-ans+mod)%mod;
        dip1[0][0]=(dp1[0][0]*dp3[0][1]%mod+dp2[0][1]*dp3[0][0]%mod)%mod;
        dip1[0][1]=(dp3[0][0]*dp2[0][0]%mod+dp3[0][1]*dp1[0][1]%mod)%mod;
        dip2[0][0]=(dp2[0][0]*dp4[0][1]%mod+dp1[0][1]*dp4[0][0]%mod)%mod;
        dip2[0][1]=(dp4[0][0]*dp1[0][0]%mod+dp4[0][1]*dp2[0][1]%mod)%mod;
        for(int i=1;i<=60;++i)
        {   dip1[i][0]=(dip1[i-1][0]*dip1[i-1][1]%mod+dip2[i-1][1]*dip1[i-1][0]%mod)%mod;
            dip1[i][1]=(dip2[i-1][0]*dip1[i-1][0]%mod+dip1[i-1][1]*dip1[i-1][1]%mod)%mod;
            dip2[i][0]=(dip2[i-1][0]*dip2[i-1][1]%mod+dip1[i-1][1]*dip2[i-1][0]%mod)%mod;
            dip2[i][1]=(dip1[i-1][0]*dip2[i-1][0]%mod+dip2[i-1][1]*dip2[i-1][1]%mod)%mod;
        }
        f[0][0]=0;f[0][1]=1;f[1][0]=0;f[1][1]=1;int res=n/2;
        for(int i=30;i>=0;--i)if(res>=(1<<i))
        {   res-=1<<i;int base1=f[0][0],base2=f[0][1],base3=f[1][0],base4=f[1][1];
            f[0][0]=(base1*dip2[i][1]%mod+base2*dip1[i][0]%mod)%mod;
            f[0][1]=(base1*dip2[i][0]%mod+base2*dip1[i][1]%mod)%mod;
            f[1][0]=(base3*dip1[i][1]%mod+base4*dip2[i][0]%mod)%mod;
            f[1][1]=(base3*dip1[i][0]%mod+base4*dip2[i][1]%mod)%mod;
        }
        if(n&1)f[0][0]=(dp1[0][1]*f[0][0]%mod+dp1[0][0]*f[1][1]%mod)%mod;
        printf("%lld\n",f[0][0]);
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM