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;
}
原文地址:https://www.cnblogs.com/AWhiteWall/p/15002813.html