Codeforces Global Round 12 D. Rating Compression (思维,双指针)

  • 题意:给你一长度为(n)的数组,有一长度为(k (1le k le n))的区间不断从左往右扫过这个数组,总共扫(n)次,每次扫的区间长度(k=i),在扫的过程中,每次取当前区间内的最小值,存到v中,问每次扫完后v中的数是否能构成一个序列.
  • 题解:我们首先特判区间长度(1)(n)的情况,这很简单,然后我们从([n-1,2])枚举区间长度(也就对应着我们枚举每次选的数(1,2...n)),不难发现,当区间长度为(n-1)时,我们要选两个数,且这两个数只能是(1,2),且(1)必须在数组的第一个位置或者最后一个位置,假如它在([2,n-1])中出现的话,我们当前的区间会向右移动一个单位,所以必然会取两次(1),当然,这同时也要求(1)在数组中只能出现一次,同时(2)必须要在数组中存在,以此向后递推其他的情况,判断我们要选的数是不是在区间的边界即可.
  • 代码:
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}

int t;
int n;
int a[N];
int ans[N];
int cnt[N];


int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>t;
	while(t--){
		cin>>n;
		rep(i,1,n) cnt[i]=0,ans[i]=0;
		rep(i,1,n) cin>>a[i],cnt[a[i]]++;

		if(cnt[1]>=1) ans[n]=1;
		
		ans[1]=1;
		rep(i,1,n){
			if(cnt[i]!=1){
				ans[1]=0;
				break;
			}
		}

		int l=1,r=n;    //因为我们每次选完后l或r的位置就被1...i-1的数占掉了,所以要移动.

		rep(i,1,n-1){
			if(!cnt[i] || cnt[i]>1) break;
			if(a[l]==i && cnt[i+1]){
				l++;
				ans[n-i]=1;
			}
			else if(a[r]==i && cnt[i+1]){
				r--;
				ans[n-i]=1;
			}
			else break;
		}

		rep(i,1,n) cout<<ans[i];
		cout<<'
';

	}

    return 0;
}
原文地址:https://www.cnblogs.com/lr599909928/p/14105006.html