10-29模拟赛题解(3合1)

盘子序列

【题目描述】
有n个盘子。盘子被生产出来后,被按照某种顺序摞在一起。初始盘堆中如果一个盘子比所有它上面的盘子都大,那么它是安全的,否则它是危险的。称初始盘堆为A,另外有一个开始为空的盘堆B。为了掩盖失误,生产商会对盘子序列做一些“处理”,每次进行以下操作中的一个:(1)将A最上面的盘子放到B最上面;(2)将B最上面的盘子给你。在得到所有n个盘子之后,你需要判断初始盘堆里是否有危险的盘子。
【输入格式】
输入文件包含多组数据(不超过10组)
每组数据的第一行为一个整数n
接下来n个整数,第i个整数表示你收到的第i个盘子的大小
【输出格式】
对于每组数据,如果存在危险的盘子,输出”J”,否则输出”Y”
【样例输入】
3
2 1 3
3
3 1 2
【样例输出】
Y
J
【数据范围】
20%的数据保证n<=8
80%的数据保证n<=1,000
100%的数据保证1<=n<=100,000,0<盘子大小<1,000,000,000且互不相等

其实呀,这个题模拟就可以了,然而我没有想到怎么模拟,然后就写了一个离散化+树状数组维护我的奇怪的结论。
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char ch=' ';int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct num{
    int id,v;
    inline bool operator < (const num& b) const {
        return v<b.v;
    }
}b[100001];
int n;
int a[100001],t[100001];
inline void update(int x,int v){
    while(x<=n){
        t[x]+=v;
        x+=x&-x;
    }
}
inline int query(int x){
    int ans=0;
    while(x){
        ans+=t[x];
        x-=x&-x;
    }
    return ans;
}
int main(){
    freopen("disk.in","r",stdin);
    freopen("disk.out","w",stdout);
    while(scanf("%d",&n)==1){
        memset(t,0,sizeof(t));
        for(int i=1;i<=n;i++)b[i].v=a[i]=read(),b[i].id=i;
        sort(b+1,b+n+1);
        for(int i=1;i<=n;i++)a[b[i].id]=i;
        int flag=1;
        for(int i=1;i<=n;++i){
            int j=i+1;
            if(query(a[i])>0){
                flag=0;
                break;
            }
            while(j<=n&&a[j]<a[j-1]){
                if(query(a[j])>0){
                    flag=0;
                    break;
                }
                ++j;
            }
            if(!flag)break;
            --j;
            update(a[j],1);update(a[i],-1);
            i=j;
        }
        if(flag)printf("Y\n");
        else printf("J\n");
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

不等数列

【题目描述】
将1到n任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。问在所有排列中,有多少个排列恰好有k个“<”。答案对2012取模。

【输入格式】
第一行2个整数n,k。

【输出格式】
一个整数表示答案。

【样例输入】
5 2
【样例输出】
66
【数据范围】
对于30%的数据:n <= 10
对于100%的数据:k < n <= 1000

这个题是原来我写过的一个题,然而这次又出出来了。。。
其实这种题呀,都有一个通用做法,我们只需要暴力打一个dfs,然后打出来10*10的表,看一看就知道了(滑稽)
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char ch=' ';int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,k;
int dp[1001][1001];
int main(){
    freopen("num.in","r",stdin);
    freopen("num.out","w",stdout);
    n=read();k=read();
    for(int i=1;i<=n;i++){
        dp[i][0]=1;
        dp[i][i]=1;
    }
    for(int i=2;i<=n;i++){
        for(int j=1;j<i;j++){
            dp[i][j]=(dp[i-1][j-1]*(i-j+1)+dp[i-1][j]*(j+1))%2012;
        }
    }
    printf("%d",dp[n-1][k]);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

点名

【题目描述】
在J班的体育课上,同学们常常会迟到几分钟,但体育老师的点名却一直很准时。老师只关心同学的身高,他会依次询问当前最高的身高,次高的身高,第三高的身高,等等。在询问的过程中,会不时地有人插进队伍里。你需要回答老师每次的询问。
【输入格式】
第一行两个整数n m,表示先后有n个人进队,老师询问了m次
第二行n个整数,第i个数Ai表示第i个进入队伍的同学的身高为Ai
第三行m个整数,第j个数Bj表示老师在第Bj个同学进入队伍后有一次询问
【输出格式】
m行,每行一个整数,依次表示老师每次询问的答案。数据保证合法
【样例输入】
7 4
9 7 2 8 14 1 8
1 2 6 6
【样例输出】
9
9
7
8
【样例解释】
(9){No.1 = 9}; (9 7){No.2 = 9}; (9 7 2 8 14 1){No.3 = 7; No.4 = 8}
【数据范围】
40%的数据保证n≤1000
100%的.据.证1≤m≤n≤30000;0≤Ai<2^32

这不是Splay裸题吗?这不是主席树裸题吗?
于是我就写了一发Splay,我旁边的hzy(dalao)写了一发主席树,嗯嗯,这就是正解,没毛病。
好,我们来说这题的暴(zheng)力(jie),其实我们可以维护一个对顶堆,然后就和我原来写过的一个题是一样的了(没错我还记得那个题叫什么,让我想上个0x3f3f3f3f min,我就知道了,嗯嗯)
算了,还是看我的Splay吧:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char ch=' ';int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int N=3e4+5;
struct ask{
    int id,num;
    inline bool operator < (const ask& b) const {
        return num<b.num;
    }
}b[N];
int n,m,sz,root;
int size[N],cnt[N],ch[N][2],f[N];
ll key[N],a[N],ans[N];
inline bool get(int x){return ch[f[x]][1]==x;}
inline void update(int x){size[x]=cnt[x]+size[ch[x][0]]+size[ch[x][1]];}
inline void clear(int x){key[x]=cnt[x]=f[x]=size[x]=ch[x][0]=ch[x][1]=0;}
inline void rotate(int x){
    int y=f[x],z=f[y],w=get(x),w2=get(y);
    ch[y][w]=ch[x][w^1];f[ch[y][w]]=y;
    ch[x][w^1]=y;f[y]=x;
    f[x]=z;if(z)ch[z][w2]=x;
    update(y);update(x);
}
inline void splay(int x){
    for(int fa=0;(fa=f[x]);rotate(x))
        if(f[fa])
            rotate((get(x)==get(fa))?fa:x);
    root=x;
}
inline void insert(ll x){
    if(!root){
        key[++sz]=x;cnt[sz]=size[sz]=1;root=sz;return;
    }
    int now=root,fa=0;
    while(1){
        if(x==key[now]){
            cnt[now]++;update(now);splay(now);return;
        }
        fa=now;
        now=ch[now][x>key[now]];
        if(!now){
            ch[fa][x>key[fa]]=++sz;
            key[sz]=x;cnt[sz]=size[sz]=1;f[sz]=fa;
            update(fa);splay(sz);return;
        }
    }
}
inline ll kth(int k){
    int now=root;
    while(1){
        if(ch[now][0]&&k<=size[ch[now][0]]){
            now=ch[now][0];
        }
        else{
            int lsize=cnt[now]+size[ch[now][0]];
            if(k<=lsize){
                return key[now];
            }
            k-=lsize;
            now=ch[now][1];
        }
    }
}
int main(){
    freopen("rollcall.in","r",stdin);
    freopen("rollcall.out","w",stdout);
    insert(-20000000000000LL);insert(20000000000000LL);
    n=read();m=read();
    for(int i=1;i<=n;i++){scanf("%lld",&a[i]);}
    for(int i=1;i<=m;i++){b[i].num=read();b[i].id=i;}
    sort(b+1,b+m+1);
    int now=1;
    for(int i=1;i<=n;i++){
        insert(a[i]);
        while(b[now].num==i){
            ans[b[now].id]=kth(b[now].id+1);
            now++;
        }
    }
    for(int i=1;i<=m;i++){
        printf("%lld\n",ans[i]);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值