zoukankan      html  css  js  c++  java
  • SDU 第七周CSP模拟题

    SDU 第七周CSP模拟题

    A

    解:数一下每种颜色袜子的个数,再除以2加到答案里即可

    #include <iostream>
    #include <cmath>
    using namespace std;
    const int N = 100010;
    void in(int &x){
    	scanf("%d",&x);
    }
    void o(int x){
    	printf("%d",x);
    }
    int n,k;
    int cnt[N];
    int main() {
        in(n);in(k);
        int ans=0;
        for(int i=1;i<=n;i++){
            int x;in(x);
            cnt[x]++;
            if(cnt[x]>1){
                cnt[x]-=2;
                ans++;
            }
        }
        o(ans);putchar('
    ');
        return 0;
    }
    

    B

    解:

    使用一个数组(以差分形式代码中的chafen[])记录任务认为每一个价格合理人数。

    那么认为价钱为i元是合理的 的人数是数组中 从1至i的和

    如:任务价钱4元合理的人数为  chafen[1]+chafen[2]+chafen[3]+chafen[4]

    维护方法:

    对于题中的每一个 [l,r]

    chafen[l]加一,chafen[r+1]减一

    #include <iostream>
    #include <cmath>
    using namespace std;
    const int N = 1000010;
    void in(int &x){
    	scanf("%d",&x);
    }
    void o(int x){
    	printf("%d",x);
    }
    int n;
    int chafen[N];//我们需要维护的差分数组
    int a[N];//还原后的数组
    signed main(){
        in(n);//输入l,r对的个数
        for(int l,r,i=1;i<=n;i++){
            in(l);in(r);
            chafen[l]+=1;
            chafen[r+1]-=1;
        }
        int maxx=0;//记录大值人数,初始化为0
        for(int i=1;i<=n;i++){
            a[i]=a[i-1]+chafen[i];
            maxx=max(maxx,a[i]);
        }
        int p=1;
        for(int i=1;i<=n;i++){//根据最大人数找出最高的价格
            if(a[i]==maxx)p=i;
        }
        o(p);putchar(' ');o(maxx);putchar('
    ');//输出答案
        return 0;
    }
    

    C

    80分:

    注意到任意一区间(l,r)存在以下两个性质:

    性质一:若 (L,R)合法,则(L,R+1), (L,R+2), (L,R+3) ,,,,,, (L,x) 等均合法。(因为剩下的数在变少)

    性质二:若(L,R)不合法,则(L+1,R)也不合法。(因为剩下的数在变多了)

    通过性质一,对于每一个L,若找到其对应的最小的合法的右端点R,那么以L为左端点的合法的区间数目为 x-R+1 ,讲其记作dp[L]。

    再根据性质二,我们若已知 L1  对应的最小的 R1  ,那么L1+1,对应的 R应该大于等于R1,于是我们可以从R1开始搜索得到L1+1 对应的最小的合法的R

    对于区间合法性的判断采用暴力搜索的办法判定。

    总时间复杂度 为 n2log(n)

    合法==符合题目要求

    #include <iostream>
    using namespace std;
    const long long N = 1000010;
    void in(long long &x){
        x=0;char c=getchar();
        long long y=1;
        while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        x*=y;
    }
    void o(long long x){
        if(x<0){x=-x;putchar('-');}
        if(x>9)o(x/10);
        putchar(x%10+'0');
    }
    long long n,x;//包子个数和包子重量上限
    long long a[N];//包子重量
    long long dp[N];//最小的右端点
    bool check(long long l,long long r){
        if(r>x)return true;//r已经加到不存在的区间了,直接退出
        long long last = -1;//判断过程中的上一个数
        for(long long i=1;i<=n;i++){
            if(l<=a[i]&&a[i]<=r)continue;//跳过被删除了的数
            if(last!=-1){//是不是开头
                if(a[i]<last)
                	return false;//比上一个数小,说明不是非递减数组,返回false
            }
            last=a[i];//记下上一个每被删的数
        }
        return true;//是非递减数组
    }
    signed main(){
        in(n);in(x);//输入包子个数和包子重量上限
        for(long long i=1;i<=n;i++)in(a[i]);//输入wi
        for(long long i=1;i<=x;i++){
            long long r=max(i,dp[i-1]);
            //找出左端点为i的合法的最小的右端点r,从max(i,dp[i-1])开始找
            while(!check(i,r))//如果当前r右端点不合法,令其+1
                r++;
            dp[i]=r;
        }
        long long ans=0;//答案
        for(long long i=1;i<=x;i++){
            ans+=(x-dp[i]+1);//统计答案
        }
        o(ans);putchar('
    ');//输出答案
        return 0;
    }
    

    100分

    利用set容器对上面做法中 判断的区间合法的过程 进行优化。(由 O(n)降低为O(log(n))

    由于我们每次判断的区间和上一次判断的相比要么是左端点加一,要么是右端点加一。

    他们是连续的。

    我们用一个stl::set 《int》st维护删除(L,R)的包子后,还剩下包子的索引。

    若 删除区间 的左端点L加了1,相当于将大小为L的包子的索引添加到st中,

    右端点R加了1,相当于将大小为R的包子的索引从st中删除。

    再定义一个变量cnt,用来维护当前数组中有多少对相邻的逆序的数,即多少个t,a[t]>a[t+1]

    当cnt为0的,当前数组是合法的,反之则不合法

    #include <bits/stdc++.h>
    using namespace std;
    const long long N = 1000010;
    void in(long long &x){
        cin>>x;
    }
    void o(long long x){
        cout<<x;
    }
    long long n,x;
    long long cnt;//逆序数量
    long long a[N],dp[N];//包子,最小的右端点
    set<long long>st;//当前数组
    vector<long long>g[N];//  g[i]中包含重量为i的所有的包子的位置
    void Add(long long x){//  把大小为x的包子加入数组中
        for(long long i=0;i<g[x].size();i++){
            auto it = st.lower_bound(g[x][i]);//二分查找的到第一个大于等于g[x][i]的元素在st的中的迭代器。
            long long last=-1,next = -1;//last 用于记录 g[x][i]的前一位,next是后一位,他们均有可能不存在
            if(it!=st.end())next=*(it);
            if(it!=st.begin())it--,last=*(it);
            if(next!=-1&&last!=-1){//均存在
                if(a[next]<a[last])cnt--;
                if(x<a[last])cnt++;
                if(a[next]<x)cnt++;
            }else if(next!=-1){//next存在
                if(a[next]<x)cnt++;
            }else if(last!=-1){//last存在
                if(x<a[last])cnt++;
            }
            st.insert(g[x][i]);//将g[x][i]加入到st中
        }
    }
    void Drop(long long x){//  将大小为x的包子从数组中删去
        for(long long i=0;i<g[x].size();i++){
            auto it = st.lower_bound(g[x][i]);
            long long next = -1,last = -1;
            it++;if(it!=st.end())next = *(it);
            it--;
            if(it!=st.begin()){
                it--;
                last = *(it);
                it++;
            }
            if(last!=-1){
                if(a[last]>x)cnt--;
            }
            if(next!=-1){
                if(a[next]<x)cnt--;
            }
            if(next!=-1&&last!=-1){
                if(a[next]<a[last])cnt++;
            }
            st.erase(g[x][i]);
        }
    }
    bool check(){
        return cnt==0;
    }
    signed main(){
        in(n);in(x);
        for(long long i=1;i<=n;i++){
            in(a[i]);
            g[a[i]].push_back(i);//将下标i加入到g[a[i]]中
        }
        for(long long i=1;i<=x;i++)Add(i);//  把所有包子加进去
        long long r = 1;
        for(long long  i=1;i<=x;i++){
            Add(i-1);//左端点i加了1,删除重量为i-1的包子
            if(r==i){//特判一下,右端点不能等于左端点
                Drop(r);//删掉r
                r++;
            }
            while(!check()){
                if(r==x+2)break;//没有有r与i对应了,退出循环
                Drop(r);r++;//删掉r
            }
            dp[i]=r-1;//记录答案
        }
        long long ans=0;//统计答案
        for(long long i=1;i<=x;i++){
            ans+=(x-dp[i]+1);
        }
        o(ans);
        putchar('
    ');
        return 0;
    }
    /*
     5 5
     1 3 2 2 4
    
     */
    
  • 相关阅读:
    服务器迁移总结
    使用OpenSSL生成证书
    mysql Event、存储过程、表命令
    负载均衡 > 常见问题
    SpringMVC记住密码功能
    spring mvc +cookie+拦截器功能 实现系统自动登陆
    android studio之argument for @notnull parameter 'name'
    jQuery ajax表单提交实现局部刷新
    Spring MVC 中采用注解方式 Action中跳转到另一个Action的写法
    ajax表单提交全路径
  • 原文地址:https://www.cnblogs.com/yesuweiYYYY/p/14670427.html
Copyright © 2011-2022 走看看