8.22 NOIP模拟测试29(B) 爬山+学数数+七十和十七

T1 爬山

二分最高高度,$O(1)$判断是否可行。

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
ll n,d,a,b,ans;
ll read()
{
    ll aa=0,bb=1;char cc=getchar();
    while(cc>'9'||cc<'0'){if(cc=='-') bb=-1;cc=getchar();}
    while(cc>='0'&&cc<='9'){aa=(aa<<3)+(aa<<1)+(cc^'0');cc=getchar();}
    return aa*bb;
}
bool check(ll x)
{
    ll ha=(x-a)/d,hb=(x-b)/d;
    if(d*ha<x-a) ha++;
    if(d*hb<x-b) hb++;
    if(ha+hb<=n-1) return true;
    return false;
}
int main()
{
    n=read();d=read();a=read();b=read();
    if(n==2){
        printf("%lld\n",max(a,b));
        return 0;
    }
    ll l=max(a,b),r=d*(n-1),mid;
    while(l<=r){
        mid=(l+r)>>1;
        if(check(mid)){
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    printf("%lld\n",ans);
    return 0;
}
爬山

T2 学数数

先离散化,用单调栈维护以一个数$x$为最大值,向左到哪,向右到哪,左$×$右就是一共有多少个区间以$x$为最大值。

用前缀和维护以$x$为最大值的区间有多少个,询问的时候$lower_bound$二分位置直接查询。

对于后$40%$的数据中,存在重复的数,那么找左右边界的时候左闭右开(左开右闭也可以),就可以避免这种情况。

记得开$long long$

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#define ll long long
using namespace std;
struct node
{
    ll x,id,l,r;
}h[100100];
ll n,Q,t[100100],p[100100];
stack<node>s;
set<ll>st;
map<ll,ll>mp;
char ch[5];
ll read()
{
    ll aa=0,bb=1;char cc=getchar();
    while(cc>'9'||cc<'0'){if(cc=='-') bb=-1;cc=getchar();}
    while(cc>='0'&&cc<='9'){aa=(aa<<3)+(aa<<1)+(cc^'0');cc=getchar();}
    return aa*bb;
}
bool cmp1(node a,node b)
{
    return a.x<b.x;
}
bool cmp2(node a,node b)
{
    return a.id<b.id;
}
int main()
{
    //freopen("test.in","r",stdin);
    //freopen("4.out","w",stdout);
    n=read();Q=read();
    for(int i=1;i<=n;i++){
        h[i].x=read();
        h[i].id=i;
        st.insert(h[i].x);
    }
    ll num=0;
    while(st.size()){
        mp[*st.begin()]=++num;
        p[num]=*st.begin();
        st.erase(*st.begin());
    }
    sort(h+1,h+n+1,cmp1);
    for(int i=1;i<=n;i++) h[i].x=mp[h[i].x];
    sort(h+1,h+n+1,cmp2);
    for(int i=1;i<=n;i++){
        ll x=h[i].x;
        while(s.size()&&s.top().x<=x) s.pop();
        if(s.size()) h[i].l=s.top().id+1;
        else h[i].l=1;
        s.push(h[i]);
    }
    while(s.size()) s.pop();
    for(int i=n;i>=1;i--){
        ll x=h[i].x;
        while(s.size()&&s.top().x<x) s.pop();
        if(s.size()) h[i].r=s.top().id;
        else h[i].r=n+1;
        s.push(h[i]);
    }
    sort(h+1,h+n+1,cmp1);
    for(int i=1;i<=n;i++){
        t[h[i].x]=t[h[i-1].x]+(h[i].id-h[i].l+1)*(h[i].r-h[i].id);
    }
    ll x;
    for(int i=1;i<=Q;i++){
        scanf("%s",ch);x=read();
        ll pos=lower_bound(p+1,p+num+1,x)-p;
        if(ch[0]=='>'){
            if(p[pos]==x) printf("%lld\n",t[num]-t[pos]);
            else printf("%lld\n",t[num]-t[pos-1]);
        }
        if(ch[0]=='='){
            if(p[pos]==x) printf("%lld\n",t[pos]-t[pos-1]);
            else puts("0");
        }
        if(ch[0]=='<'){
            if(p[pos]==x) printf("%lld\n",t[pos-1]);
            else printf("%lld\n",t[pos-1]);
        }
    }
    return 0;
}
学数数

T3 七十和十七

设$f[i]$为长度为$i$的序列(不是排列)中计数器的大小。假设现在已知$f[i-1]$

那么第$i$位与前面的相对大小关系一共有i种

1.第$i$位相对大小为i,对计数器没有任何影响,直接转移 $f[i]=f[i-1]$

2.第$i$位相对大小小于$i$ (即$1~i-1$),设为$j$,那么计数器的值就需要增加$2^{j-1}$ (可以拿几个数试一下),对于前$i-1$个数,他们的顺序有$(i-1)!$种,所以$ f[i]=f[i-1]+2^{j-1}*(i-1)!$

综上,

$f[i]=f[i-1]+(f[i-1]+2^{1-1}*(i-1)!)+(f[i-1]+2^{2-1}*(i-1)!)+(f[i-1]+2^{3-1}*(i-1)!)...+(f[i-1]+2^{i-1-1}*(i-1)!)$

发现$2$的多少次方是一个等比数列,可以直接用前$i-1$项和公式求出来,剩下$i$个$f[i-1]$相加

最终得到$f[i]=f[i-1]*i+(2^{i-1}-1)*(i-1)!$

答案即为$f[n]/n!$

#include<iostream>
#include<cstdio>
#define mod 1000000007
#define ll long long
using namespace std;
ll n,ans,f[100100];
ll quick(ll x,ll p)
{
    ll as=1;
    while(p){
        if(p&1) as=as*x%mod;
        x=x*x%mod;
        p>>=1;
    }
    return as;
}
int main()
{
    scanf("%lld",&n);
    ll sum=1,tot=1;
    for(ll i=1;i<=n;i++){
        f[i]=(f[i-1]*i%mod+(tot-1)*sum%mod)%mod;
        tot=tot*2%mod;
        sum=sum*i%mod;
    }
    printf("%lld\n",f[n]*quick(sum,mod-2)%mod);
    return 0;
}
七十和十七

猜你喜欢

转载自www.cnblogs.com/jrf123/p/11396254.html
今日推荐