• Codeforces Global Round 12


    (sf D-Rating Compression)

    题目

    简要题意

    给定一个长度为 (n) 的序列 (a),定义 “(k) 级青白给” 为一个序列 (b),其中每个元素 (b_i) 可以被表示为 (min_{j=i}^{i+k-1} a_j)

    现在请你判断,对于 (i=1ldots n),“(i) 级青白给” 是否为一个排列。

    数据范围与提示

    有多组数据 (le 10^4)(1le nle 3 imes 10^5, 1le a_ile n),且 (sum nle 3 imes 10^5)

    解法

    #1. 一种方法

    (1) 级青白给” 比较特殊,特判序列 (a) 本身是否为排列即可。

    观察题目样例可得,“(i) 级青白给” 是否为排列是有依赖性的。即若 “(i+1) 级青白给” 不是排列,那么 “(i) 级青白给” 也不是排列。

    为什么呢?考虑不合法的 “(i+1) 级青白给”,要么 (a) 没有 (1ldots n-i) 种数,要么 (b) 出现了重复的数字。

    如果没有这么多种,肯定也无法满足 “(i) 级青白给” 的标准;如果出现重复数字,级别越小重复概率越大。

    这样我们自然地想到从 “(n) 级青白给” 开始判断,直接判断区间最小值是否为 (1)。对于 “(n-1) 级青白给”,我们需要保证 (1)(1)(n) 号位,且序列存在 (2),以此类推…

    我们发现,这类似于将区间 ([1,n]) 从边界缩小的过程。

    注意对于重复的数字 (x),它会使级别小于 (n-x+1) 的青白给不为排列,但除此之外的青白给是不受影响的。

    #2. 另一种方法

    (mathtt {By} sf xjx)

    其实是另一种实现方法。

    定义 void solve(l,r,m,d) 为当前区间为 ([l,r]),还有 “([1,m]) 级别的青白给” 没有填答案,填到数字 (d)(当然也可以用循环)。

    详见注释。

    代码

    #1. 一种方法

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
    #define print(x,y) write(x),putchar(y) 
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    
    const int maxn=3e5+5;
    
    vector <int> ans;
    int n,a[maxn],num[maxn];
    
    int main() {
    	rep(T,1,read(9)) {
    		n=read(9); ans.clear();
    		rep(i,1,n) a[i]=read(9),++num[a[i]];
    		int l=1,r=n;
    		rep(i,1,n-1) {
    			if(num[i]) ans.push_back(1);
    			if(a[l]==i or a[r]==i) {
    				if(a[l]==i) ++l;
    				else --r;
    			}
    			else break;
    			if(num[i]>1) break;
    		}
    		rep(i,1,n-ans.size()-1) ans.push_back(0);
    		bool flag=true;
    		rep(i,1,n) {
    			if(!num[a[i]]) flag=false;
    			num[a[i]]=0;
    		}
    		ans.push_back(flag);
    		for(int i=ans.size()-1;i>=0;--i) write(ans[i]); puts("");
    	}
    	return 0;
    }
    

    #2. 另一种方法

    #include<cstdio>//JZM YYDS!!!
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<string>
    #include<map>
    #include<ctime>
    #define ll long long
    #define MAXN 300005
    #define uns unsigned
    #define MOD 998244353ll
    #define INF 0x3f3f3f3f
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    inline ll read(){
    	ll x=0;bool f=1;char s=getchar();
    	while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
    	while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar();
    	return f?x:-x;
    }
    int n,a[MAXN],num[MAXN],b[MAXN];
    bool ans[MAXN];
    inline void solve(int l,int r,int m,int d){
    	if(l>r||d>n)return;
    	// 未出现此数字
    	if(num[d]==0){
    		for(int i=1;i<=m;i++)ans[i]=0;
    		return;
    	}
    	// 此数字出现不止一次
    	if(num[d]>1){
    		for(int i=1;i<=min(r-l,m);i++)ans[i]=0;
    		// r-l+1 已经确定
    		return;
    	}
    	// 此数字只出现一次却不在边界上
    	if(b[d]>l&&b[d]<r){
    		for(int i=2;i<=min(r-l,m);i++)ans[i]=0;
    		solve(l,r,1,d+1);
    		// 特判 k=1 的情况
    	}
    	else if(b[d]==l)solve(l+1,r,min(m,r-l),d+1);
    	else solve(l,r-1,min(m,r-l),d+1);
    }
    signed main()
    {
    	for(int T=read();T--;){
    		n=read();
    		for(int i=1;i<=n;i++)num[i]=0;
    		for(int i=1;i<=n;i++)
    			a[i]=read(),b[a[i]]=i,num[a[i]]++,ans[i]=1;
    		solve(1,n,n,1);
    		for(int i=1;i<=n;i++)putchar('0'+ans[i]);
    		putchar('
    ');
    	}
    	return 0;
    }
    

    (sf F-The Struggling Contestant)

    解法

    可以看一看这个太太的博客,我只是基于自己不太懂的地方进行阐释。

    • 为什么 (f(z)le 2k+2-f(x))。总端点数减去 (x) 作为端点出现的次数。
    • 最多只会存在一个 (x) 满足 (f ( x ) > k + 2)。同理,还是考虑总端点数为 (2k+2)

    最后需要特判作为端点次数最多的 (x) 是否能找到足够的 (y) 与其配对。

    代码

    #include <bits/stdc++.h>
    using namespace std;
     
    #define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
    #define print(x,y) write(x),putchar(y) 
     
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
    
    const int maxn=1e5+5;
    
    int n,a[maxn],num[maxn],cnt[maxn];
    
    int main() {
    	rep(T,1,read(9)) {
    		n=read(9); int k=0;
    		rep(i,1,n) a[i]=read(9),num[i]=cnt[i]=0;
    		rep(i,1,n) ++num[a[i]];
    		rep(i,2,n) 
    			if(a[i]==a[i-1]) cnt[a[i]]+=2,++k;
    		++cnt[a[1]],++cnt[a[n]];
    		int max_cnt=0,max_num=0;
    		rep(i,1,n) {
    			max_cnt=Max(max_cnt,cnt[i]);
    			max_num=Max(max_num,num[i]);
    		}
    		if(max_num*2>n+1) puts("-1");
    		else print(k+Max(0,max_cnt-(k+2)),'
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    你不知道的 JavaScript 系列中( 21 ) -尽量不要使用 Object()/Function()/RegExp()
    你不知道的 JavaScript 系列中( 20 ) - 永远不要创建和使用空单元数组
    你不知道的 JavaScript 系列中( 19 ) - 封装对象拆封
    你不知道的 JavaScript 系列中( 18 ) - 封装对象包装
    你不知道的 JavaScript 系列中( 17 ) - 内部属性[[Class]]
    你不知道的 JavaScript 系列中( 16 ) - 原生函数
    node 切换 安装
    Mac  nginx  安装
    cnpm 安装
    2020年面试及入职新公司的痕迹
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/15002813.html
Copyright © 2020-2023  润新知