链接:http://codeforces.com/contest/1208/problem/B
题意:问去掉最小多少的一段能使所有不同数字的个数为1。
题解:以去掉的长度为基准进行二分,因为ai能到达1e9,所以还要离散化,然后直接暴力查询即可。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<stack>
#include<cstring>
#include<map>
#include<queue>
#include<cmath>
#include<set>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
#define speed std::ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
using namespace std;
typedef long long ll;
queue<int> q;
priority_queue<int> pq;
const int maxn = 2005;
ll n,m;
ll ans=INF,cnt=0;
ll a[maxn],b[maxn];
bool check(ll x)
{
ll c[maxn];
ll i,j,k;
for(i=1;i<=n-x+1;i++){
memset(c,0,sizeof(c));
for(j=1;j<=i-1;j++){
c[a[j]]++;
if(c[a[j]]>1)
break;
}
for(k=i+x;k<=n;k++){
c[a[k]]++;
if(c[a[k]]>1)
break;
}
if(k==n+1&&j==i)
return true;
}
return false;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
b[i]=a[i];
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
if(b[i]!=b[cnt])
b[++cnt]=b[i];
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
/*for(int i=1;i<=n;i++)
cout<<a[i]<<endl;*/
ll l=0,r=n-1,mid=(l+r)/2;;
while(l<=r){
//cout<<mid<<endl;
if(check(mid)){
r=mid-1,ans=min(mid,ans);
}
else
l=mid+1;
mid=(l+r)/2;
}
cout<<ans<<endl;
return 0;
}
看到了tourist的做法,感觉可以学习一下vector容器离散化的方法和去重的手法,下面是他的代码和我的解释
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
vector<int> b = a;
sort(b.begin(), b.end()); //unique的返回值为不重复元素的最后一个位置
b.resize(unique(b.begin(), b.end()) - b.begin()); //重新调整b容器的大小为不重复元素的终点到起点大小
//cout<<b.size()<<endl; //unique去除相邻的重复元素
if ((int) b.size() == n) { //如果相等则无重复
cout << 0 << '\n';
return 0;
}
for (int i = 0; i < n; i++) {
a[i] = (int) (lower_bound(b.begin(), b.end(), a[i]) - b.begin());
} //离散化
int ans = 0;
vector<int> mark(n, 0);v //二维数组,每项初始化为零
for (int i = 0; i < n; i++) { //左边
int take = 0;
for (int j = 0; j < n; j++) { //从后面往前,右边
if (mark[a[n - 1 - j]] > 0) { //如果大于零则说明加上这个数字则不符合要求了
break;
}
mark[a[n - 1 - j]] = 1; //标记已出现过
++take; //记录取了几个数字
}
ans = max(ans, i + take); //i是左边取得数字,take是右边取得数字
for (int j = 0; j < take; j++) {
mark[a[n - 1 - j]] = 0; //将右边的数字还原
}
if (mark[a[i]]) { //出现重复则说明左边走到终点了,不能再往下
break;
}
mark[a[i]] = 1; //记录这个数字已出现过
}
cout << n - ans << '\n';
return 0;
}