Codeforces Round #436 div 2 A B C D 题解

A:题意 给N个数 如果N只有两种相同数目的数字,输出YES,否则输出NO

思路:统计下数目就好了,水题


B:题意 给N个大写 /小写字母,选若干不同的小写字母,且小写字母之间不能有大写字母,问最多能选多少个小写字母

思路:设一个set<char>a[N],以大写字母为分界点,各部分用set存起来去重即可,输出大小最大的set,水题


C:题意:a距离来回k次,f处有加油站,问来回k次最少加油的次数

加油问题:给若干加油站的位置和能加的油量,起始油量及油量上限,终点的位置,问最少加多少次油

思路:经过一次加油站相当于获得了一次加油的机会。

pos:当前位置,初始化为0

tank:油量,初始化为b

jiayou[i]:  1<=i<=k+1, k+1个加油站的位置, 第k+1个加油站是终点

count:加油的机会,初始化为0;每经过一个加油站就+1,加一次油就-1;

ans:加油的次数,初始化为0

遍历所有加油站,对于每个加油站i,更新当前走过的距离d=jiayou[i]-pos,

若tank比d少,说明这段d距离的路不够油走(极端是刚好到不了i加油站),

就需要不断加油(每次加油更新变量tank count ans),加油直到tank比d大,那么就可以到达第i个加油站,到达后更新tank 和count即可

这里每个加油站加的油都固定的,(如果每个加油站油量不同,那么就需要优先队列来加前面1~i-1最大量的油站的油),简单题


D:题意,给N个数a[N],问最少改变多少个数,使得这N个数成为1~N的一个排列,并输出最小序的解。

思路:定义last数组 last[a[i]]=i,含义是a[i]最后出现的下标是多少,比如4 3 2 2 2,last[2]=5,last[3]=2,last[4]=1

显然,剩下的last[1]=0和last[5]=0,说明这个数列还缺少1和5,所以我们要让其中的两个数变成1,5,

而且发现最少修改的次数就是last[j]=0的j的个数

要输出最小序的解,所以设一个最小值优先的优先队列qq,把缺少的数字1,5存起来

遍历i=1~N,如果当前的i满足last[a[i]]!=i (即当前数字i不是a[i]=k最后出现的下标,即后面还有一样的k),

那么这个a[i]就可以修改成别的,修改成什么呢,我们要最小序,所以a[i]=qq.top();

上面的思路,举个例子:43222-》43122-》43152

当然,上面的思路有缺陷,如果是11223,缺少4,5,如果按照上面的思路就会改成4 1 5 2 3,这答案不对,应该把第二个1改成4才对,所以我们加两个条件:a[i]>qq.top()且qq不空,防止小的数提前被大的数修改掉,qq里比较大的数要在后面修改,

我们还需要一个vis数组,记录当前a[i]出现了这种情况,对于下一个a[i]=k就一定要用qq的数来修改(再不改就出现两个k了)

所以对于每次修改之后我们都要把修改后的vis[a[i]]设为1,说明我们已经存在a[i]了,后面再遇到a[i]就要用qq的数来修改了!


代码部分:

A:略

B:

set<char> a[205];
char cs[205];
int main()
{
	int n;
	scanf("%d",&n);
	int num=0;
	getchar();
	for(int i=1; i<=n; i++)
		scanf("%c",&cs[i]);
	cs[0]='B';
	for(int i=1; i<=n; i++)
	{
		if(isupper(cs[i]))
		{
			continue;
		}
		if(!isupper(cs[i]))
		{
			if(isupper(cs[i-1]))
			{
				num++;
			}
			a[num].insert(cs[i]);
		}
	}
	if(num==0)
	{
		printf("0\n");
		return 0;
	}
	int maxs=0;
	for(int i=1; i<=num; i++)
		maxs=max(maxs,(int)a[i].size());
	printf("%d\n",maxs);
	return 0;
}
C:

int main()
{
	ll a,b,f,k;
	cin>>a>>b>>f>>k;
	ll total=a*k;//length 
	ll jiayou[10005];
	for(int i=1;i<=k;i++)
	{
		if(i%2==1)
		jiayou[i]=f+(i-1)*a;
		else
		jiayou[i]=2*a-f+(i-2)*a;
	}
	jiayou[k+1]=total;
	ll pos=0;//当前位置 
	ll tank=b;//当前油量 
	ll count=0;//加油站数目 
	ll ans=0;
	for(int i=1;i<=k+1;i++)
	{
		ll d=jiayou[i]-pos;
		while(tank-d<0)
		{
			if(count==0)
			{
				printf("-1\n");
				return 0;
			}
			tank=b;
			ans++;
			count--;
		}
		tank-=d;
		pos=jiayou[i];
		count++;
	}
	cout<<ans<<endl;
	return 0;
}
D:

#define scann(d) scanf("%d",&d)
using namespace std;
const int N=2e5+10;
int n,a[N],last[N];
bool vis[N];
int main()
{
	scann(n);
	for(int i=1; i<=n; i++)
	{
		scann(a[i]);
	}
	for(int i=1; i<=n; i++)
	{
		last[a[i]]=i;//数字a[i] 最后出现的下标 
	}
	priority_queue<int, vector<int>, greater<int> > h;
	for(int i=1; i<=n; i++)
	{
		if ( last[i]==0 ) h.push(i);
	}
	for(int i=1; i<=n; i++)
	{
		cout<<"last:"<<last[i]<<endl;
	}
	int ans=0;
	for(int i=1; i<=n; i++)
	{
		if ( vis[a[i]] || (last[a[i]]!=i && !h.empty() && h.top()<a[i]) )
		{
			cout<<vis[a[i]]<<" "<<i<<"h.top:"<<h.top()<<endl;
			ans++;
			a[i]=h.top();
			h.pop();
		}
		vis[a[i]]=1;
	}
	printf("%d\n",ans);
	for(int i=1; i<=n; i++)
		printf("%d ",a[i]);
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值