您的位置:首页 > 其它

Codeforces Round #315 div2 B-Inventory 标记,水题

2015-08-11 10:44 267 查看
链接
codeforce 569B

题目意思很明确,给出n个数,要求你将其中的若干个数字调整,使得最终这n个数恰好为1~n的一个排列,即所有数字在[1,n]中且互不相同,并且被调整的数字尽量少。

总体上只要是“碰到不符合题意的数字就改掉”的思路貌似都能保证被调整的数字尽量少。。这个地方似乎没难度。

唯一可能会卡的地方就是规模为10^5,算法不好的话可能会超时。

还有就是我犯的低级错误。。都是泪

对每个样例,将所有数字读入并且在读入的过程中标记下每个数字出现的次数,用vis数组记录。而后写第二个循环,将1~n中在原始序列里面没有用到的数字找出来存到另一个开辟出来的数组b中。而后再开始第三个循环,将原始序列中每一个不符合要求(重复出现或不介于1到n)的数字改掉,改成的目标数字从b数组中找,因为b数组中仅存储了没用过的数字,所以这个查找是常数级的

并且记得,对于介于1到n且被重复使用的数字,每次更改之后要将对应的vis值减一,这样最终的序列会保证该数字恰好用了一次,否则该数字所有出现的位置将全部被改掉。

由于是3个10^5级别的循环并列。。所以算法依然是O(N)的,并不超时

说的挺乱的好像。。看代码可能可以更清楚点

code:

By skyword, contest: Codeforces Round #315 (Div. 2), problem: (B) Inventory, Accepted, #
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<cstring>
#include<vector>
#define maxn 100010
int n;
int a[maxn],vis[maxn],b[maxn];
int main()
{
scanf("%d",&n);
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
vis[a[i]]++;
}
for(int i=1,j=0;i<=n;i++)
{
if(vis[i]==0)
b[j++]=i;
}
for(int i=0,j=0;i<n;i++)
{
if((vis[a[i]]>1)||(a[i]<1)||(a[i]>n))
{
vis[a[i]]--;
a[i]=b[j];
j++;

}
}
for(int i=0;i<n;i++)
{
printf("%d",a[i]);
if(i<n-1) printf(" ");
else printf("\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: