CODEFORCE ROUND #625 DIV2

不得不说cf题目都是毒瘤,一篇读下来我头都裂开了 (哭)

个人认为这次的大坑点是E题 不谈有生之年的F题

和平常一样A,B,C都是思维题不过这次C题有坑还是贴一下

C题:

https://codeforces.ml/contest/1321/problem/C

You are given a string ss consisting of lowercase Latin letters. Let the length of ss be |s||s|. You may perform several operations on this string.

In one operation, you can choose some index ii and remove the ii-th character of ss (sisi) if at least one of its adjacent characters is the previous letter in the Latin alphabet for sisi. For example, the previous letter for b is a, the previous letter for s is r, the letter a has no previous letters. Note that after each removal the length of the string decreases by one. So, the index ii should satisfy the condition 1≤i≤|s|1≤i≤|s| during each operation.

For the character sisi adjacent characters are si−1si−1 and si+1si+1. The first and the last characters of ss both have only one adjacent character (unless |s|=1|s|=1).

Consider the following example. Let s=s= bacabcab.

  1. During the first move, you can remove the first character s1=s1= b because s2=s2= a. Then the string becomes s=s= acabcab.
  2. During the second move, you can remove the fifth character s5=s5= c because s4=s4= b. Then the string becomes s=s= acabab.
  3. During the third move, you can remove the sixth character s6=s6='b' because s5=s5= a. Then the string becomes s=s= acaba.
  4. During the fourth move, the only character you can remove is s4=s4= b, because s3=s3= a (or s5=s5= a). The string becomes s=s= acaa and you cannot do anything with it.

Your task is to find the maximum possible number of characters you can remove if you choose the sequence of operations optimally.Input

The first line of the input contains one integer |s||s| (1≤|s|≤1001≤|s|≤100) — the length of ss.

The second line of the input contains one string ss consisting of |s||s| lowercase Latin letters.Output

Print one integer — the maximum possible number of characters you can remove if you choose the sequence of moves optimally.

题目大意就是给你n个字母,这个字母能被删除的条件是相邻的字母存在ASCII比他小1,问最多能删几个字母。

这里的坑就是你当前枚举的最高字母要多遍历几遍,如果只遍历一遍那

bbbbbbbb a bbbbb这种样例就会输出a前面一个加后面所有b的个数这样明显不对

刚开始不知道string有erase函数搞得我头皮发麻

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<set>
#include<list>
#include<vector>
#include<string>
using namespace std;
const int N=107;
int n,ans;
string s;
int main()
{
	scanf("%d",&n);
	getchar();
	cin>>s;
	for(int i='z';i>='a';i--)
	{
		for(int k=100;k>=0;k--)//多遍历几次
		{
			for(int j=0;j<s.size();j++)
			{
				if(i==s[j])
				{
					if(s[j]-s[j-1]==1||s[j]-s[j+1]==1)
					{
						ans++;
						s.erase(j,1);
						j--;
					}
				}
			}
		} 
	} 
	printf("%d",ans);
	return 0;
} 

  

D题:

https://codeforces.ml/contest/1321/problem/D

The map of Bertown can be represented as a set of nn intersections, numbered from 11 to nn and connected by mm one-way roads. It is possible to move along the roads from any intersection to any other intersection. The length of some path from one intersection to another is the number of roads that one has to traverse along the path. The shortest path from one intersection vv to another intersection uu is the path that starts in vv, ends in uu and has the minimum length among all such paths.

Polycarp lives near the intersection ss and works in a building near the intersection tt. Every day he gets from ss to tt by car. Today he has chosen the following path to his workplace: p1p1, p2p2, ..., pkpk, where p1=sp1=s, pk=tpk=t, and all other elements of this sequence are the intermediate intersections, listed in the order Polycarp arrived at them. Polycarp never arrived at the same intersection twice, so all elements of this sequence are pairwise distinct. Note that you know Polycarp's path beforehand (it is fixed), and it is not necessarily one of the shortest paths from ss to tt.

Polycarp's car has a complex navigation system installed in it. Let's describe how it works. When Polycarp starts his journey at the intersection ss, the system chooses some shortest path from ss to tt and shows it to Polycarp. Let's denote the next intersection in the chosen path as vv. If Polycarp chooses to drive along the road from ss to vv, then the navigator shows him the same shortest path (obviously, starting from vv as soon as he arrives at this intersection). However, if Polycarp chooses to drive to another intersection ww instead, the navigator rebuilds the path: as soon as Polycarp arrives at ww, the navigation system chooses some shortest path from ww to tt and shows it to Polycarp. The same process continues until Polycarp arrives at tt: if Polycarp moves along the road recommended by the system, it maintains the shortest path it has already built; but if Polycarp chooses some other path, the system rebuilds the path by the same rules.

Here is an example. Suppose the map of Bertown looks as follows, and Polycarp drives along the path [1,2,3,4][1,2,3,4] (s=1s=1, t=4t=4):

Check the picture by the link http://tk.codeforces.com/a.png

  1. When Polycarp starts at 11, the system chooses some shortest path from 11 to 44. There is only one such path, it is [1,5,4][1,5,4];
  2. Polycarp chooses to drive to 22, which is not along the path chosen by the system. When Polycarp arrives at 22, the navigator rebuilds the path by choosing some shortest path from 22 to 44, for example, [2,6,4][2,6,4] (note that it could choose [2,3,4][2,3,4]);
  3. Polycarp chooses to drive to 33, which is not along the path chosen by the system. When Polycarp arrives at 33, the navigator rebuilds the path by choosing the only shortest path from 33 to 44, which is [3,4][3,4];
  4. Polycarp arrives at 44 along the road chosen by the navigator, so the system does not have to rebuild anything.

Overall, we get 22 rebuilds in this scenario. Note that if the system chose [2,3,4][2,3,4] instead of [2,6,4][2,6,4] during the second step, there would be only 11 rebuild (since Polycarp goes along the path, so the system maintains the path [3,4][3,4] during the third step).

The example shows us that the number of rebuilds can differ even if the map of Bertown and the path chosen by Polycarp stays the same. Given this information (the map and Polycarp's path), can you determine the minimum and the maximum number of rebuilds that could have happened during the journey?Input

The first line contains two integers nn and mm (2≤n≤m≤2⋅1052≤n≤m≤2⋅105) — the number of intersections and one-way roads in Bertown, respectively.

Then mm lines follow, each describing a road. Each line contains two integers uu and vv (1≤u,v≤n1≤u,v≤n, u≠vu≠v) denoting a road from intersection uu to intersection vv. All roads in Bertown are pairwise distinct, which means that each ordered pair (u,v)(u,v) appears at most once in these mm lines (but if there is a road (u,v)(u,v), the road (v,u)(v,u) can also appear).

The following line contains one integer kk (2≤k≤n2≤k≤n) — the number of intersections in Polycarp's path from home to his workplace.

The last line contains kk integers p1p1, p2p2, ..., pkpk (1≤pi≤n1≤pi≤n, all these integers are pairwise distinct) — the intersections along Polycarp's path in the order he arrived at them. p1p1 is the intersection where Polycarp lives (s=p1s=p1), and pkpk is the intersection where Polycarp's workplace is situated (t=pkt=pk). It is guaranteed that for every i∈[1,k−1]i∈[1,k−1] the road from pipi to pi+1pi+1 exists, so the path goes along the roads of Bertown.Output

Print two integers: the minimum and the maximum number of rebuilds that could have happened during the journey.

题目大意就是n个点m条单向边,没有重边自环大概 给你一条初始路径(u,v),判断这条路径上的点是否符合最短路径,如果不符合就会重新导航问你最大和最小重新导航的次数比如(u,v)=1,2,3,4有这样一个图

从1到4的最短路是1,5,4而路径会从1到2,不满足最短路就重新导航,2到4的最短路有2, 3, 4,2,6,4两条,若求最大值则系统应显示出264这样从2到3系统就会重新导航一次,如果系统本身显示的是234则从2到3满足路线就不会重新导航(求最小值)

想想最短路的定义,dis i=dis j+w则是i到j的最短路这里判断固定路线z中相邻两点是不是的最短路只需判断dis[a1]?=dis[a2]+1

如果等于:求最小值则ansminn不用加,求最大值则枚举a1的子节点若还存在一条最短路(dis children==dis a2)则ansmaxn++否则ansmaxn不加

如果不想等则肯定要重新导航ansminn,ansmaxn都加

求所有点到终点的最短路要反向建图

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<set>
#include<list>
#include<vector>
#include<string>
#include<queue>
using namespace std;
const int N=2e5+7,inf=0x3f3f3f3f;
int n,m,ansmaxn,ansminn,x,y,k,a[N],dis[N];
bool use[N];
queue < int > q;
vector < int > f1[N],f[N];
void spfa(int x)
{
	for(int i=1;i<=n;i++)
		dis[i]=inf;
	//memset(dis,inf,sizeof(dis));
	dis[x]=0;
	q.push(x);
	while(!q.empty())
	{
		int temp=q.front();
		q.pop();
		use[temp]=0;
		for(int i=0;i<f[temp].size();i++)
		{
			int xx=f[temp][i];
			if(dis[xx]>dis[temp]+1)
			{
				dis[xx]=dis[temp]+1;
				if(use[xx]==0)
				{
					use[xx]=1;
					q.push(xx);
				}
			}
		}
	}
	return ;	
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d %d",&x,&y);
		f[y].push_back(x);//反向建图求dis
		f1[x].push_back(y);//正向建图求子节点
	}
	scanf("%d",&k);
	for(int i=1;i<=k;i++)
		scanf("%d",&a[i]);
	spfa(a[k]);
	/*for(int i=1;i<=n;i++)
	{
		printf("%d ",dis[i]);
	}*/
	for(int i=1;i<k;i++)
	{
		if(dis[a[i]]==dis[a[i+1]]+1)
		{
			for(int j=0;j<f1[a[i]].size();j++)//枚举子节点
			{
				int temp=f1[a[i]][j];
				if(dis[temp]==dis[a[i+1]]&&temp!=a[i+1])
				{
					ansmaxn++;
					break;
				}
			}
		}
		else
		{
			ansmaxn++;
			ansminn++;
		}
	}
	printf("%d %d",ansminn,ansmaxn);
	return 0;
} 

  

E题:

这题坑我快5个小时

现在过了我只想默默说一句 f**k

Roma is playing a new expansion for his favorite game World of Darkraft. He made a new character and is going for his first grind.

Roma has a choice to buy exactly one of nn different weapons and exactly one of mm different armor sets. Weapon ii has attack modifier aiai and is worth caicai coins, and armor set jj has defense modifier bjbj and is worth cbjcbj coins.

After choosing his equipment Roma can proceed to defeat some monsters. There are pp monsters he can try to defeat. Monster kk has defense xkxk, attack ykyk and possesses zkzk coins. Roma can defeat a monster if his weapon's attack modifier is larger than the monster's defense, and his armor set's defense modifier is larger than the monster's attack. That is, a monster kk can be defeated with a weapon ii and an armor set jj if ai>xkai>xk and bj>ykbj>yk. After defeating the monster, Roma takes all the coins from them. During the grind, Roma can defeat as many monsters as he likes. Monsters do not respawn, thus each monster can be defeated at most one.

Thanks to Roma's excessive donations, we can assume that he has an infinite amount of in-game currency and can afford any of the weapons and armor sets. Still, he wants to maximize the profit of the grind. The profit is defined as the total coins obtained from all defeated monsters minus the cost of his equipment. Note that Roma must purchase a weapon and an armor set even if he can not cover their cost with obtained coins.

Help Roma find the maximum profit of the grind.Input

The first line contains three integers nn, mm, and pp (1≤n,m,p≤2⋅1051≤n,m,p≤2⋅105) — the number of available weapons, armor sets and monsters respectively.

The following nn lines describe available weapons. The ii-th of these lines contains two integers aiai and caicai (1≤ai≤1061≤ai≤106, 1≤cai≤1091≤cai≤109) — the attack modifier and the cost of the weapon ii.

The following mm lines describe available armor sets. The jj-th of these lines contains two integers bjbj and cbjcbj (1≤bj≤1061≤bj≤106, 1≤cbj≤1091≤cbj≤109) — the defense modifier and the cost of the armor set jj.

The following pp lines describe monsters. The kk-th of these lines contains three integers xk,yk,zkxk,yk,zk (1≤xk,yk≤1061≤xk,yk≤106, 1≤zk≤1031≤zk≤103) — defense, attack and the number of coins of the monster kk.Output

Print a single integer — the maximum profit of the grind.

题目大意是输入n,m,p有n个攻击装备,m个防御装备,p个怪物每个怪物被打败后都会有钱并且怪物每个只能打一次

攻击装备和防御装备各买一个(即使怪物得到的钱很少也要买),且装备都有两个值 attack ,cost

能打败怪物的条件是n attack>p def && m defense>p atk注意怪物是先输入def再是atk而装备相反。

求获得的利润最大值 打败怪物获得的钱-装备花费的钱

后来才知道这样的东西叫 二维偏序  听说624的F题也是这个?!!

就是先将一维x放进线段树维护,另一维y排序,然后根据枚举的y ask线段树得出答案

这种代码时用一种特殊的方式排序,后来直接o1查询 值得借鉴

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<set>
#include<list>
#include<vector>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
const int N=2e5+7,M=1e6+5;
const long long inf=0xfffffffff;
int n,m,p;
long long ca[M+5],cb[M+5],acost,bcost,a[N],b[N],ans=-inf;
//ca,cb数组小心越界 
struct node 
{
	long long at,w,def;//atk==x装备的def==x 
	bool operator <(const node &t)const{return def<t.def;}
}c[N];
struct node3
{
	long long sum,maxn,add;
}t[M*4];
long long max(long long x,long long y)
{
	if(x>y)
		return x;
	return y;
}
void built(int p,int l,int r)
{
	t[p].add=0;
	if(l==r)
	{
		t[p].maxn=-cb[l];
		//t[p].sum=-b[l].w;
		return ;
	}
	int mid=(l+r)/2;
	built(p*2,l,mid);
	built(p*2+1,mid+1,r);
	t[p].maxn=max(t[p*2].maxn,t[p*2+1].maxn);
	//t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
void push_tag(int p,int l,int r)
{
	if(t[p].add)
	{
		t[p*2].add+=t[p].add;
		t[p*2+1].add+=t[p].add;
		t[p*2].maxn+=t[p].add;
		t[p*2+1].maxn+=t[p].add;
		t[p].add=0;
	}
	return ;
}
void push_down(int p)
{
	t[p].maxn=max(t[p*2].maxn,t[p*2+1].maxn);
}
void up(int p,int qx,int zx,int gl,int gr,int k)//区间加操作 
{
	if(qx>=gl&&zx<=gr)
	{
		t[p].add+=k;
		t[p].maxn+=k;
		return ;
	}
	int mid=(qx+zx)/2;
	push_tag(p,qx,zx);
	if(gl<=mid)
		up(p*2,qx,mid,gl,gr,k);
	if(gr>mid)
		up(p*2+1,mid+1,zx,gl,gr,k);
	push_down(p);
	return ;
}

long long askmaxn(int p,int qx,int zx,int gl,int gr)//查询最大值 
{
	if(qx>=gl&&zx<=gr)
	{
		return t[p].maxn;
	}
	int mid=(qx+zx)/2;
	long long ans=-inf;
	push_tag(p,qx,zx);
	if(gl<=mid)	
		ans=max(ans,askmaxn(p*2,qx,mid,gl,gr));
	if(gr>mid)
		ans=max(ans,askmaxn(p*2+1,mid+1,zx,gl,gr));
	return ans;
}
int main()
{
	scanf("%d %d %d",&n,&m,&p);
	for(int i=1;i<=M+1;i++)
	{
		ca[i]=inf;//攻击为i时所要的最小的钱 
		cb[i]=inf;//防御为i时所要的最小的钱 
	}
	for(int i=1;i<=n;i++)
	{	
		scanf("%lld %lld",&a[i],&acost);
		ca[a[i]]=min(ca[a[i]],acost); 
	} 
	for(int i=1;i<=m;i++)
	{
		scanf("%lld %lld",&b[i],&bcost);
		cb[b[i]]=min(cb[b[i]],bcost);
	}
	for(int i=M;i>=1;i--)
	{
		ca[i]=min(ca[i],ca[i+1]);
		cb[i]=min(cb[i],cb[i+1]);//如果防御力为i存在铠甲则有i-1防御力铠甲的代价最小仍为cb[i] 
	}
	built(1,1,M);//防御力线段树 
	for(int i=1;i<=p;i++)
		scanf("%lld %lld %lld",&c[i].def,&c[i].at,&c[i].w);
	sort(c+1,c+p+1);//monster 防御力从小到大 
	ans=-ca[1]-cb[1];
	//printf("%lld %lld\n",ca[1],cb[1]);
	for(int i=1;i<=p;i++)
	{
		up(1,1,M,c[i].at+1,M,c[i].w); 
		//先假设剑的攻击力都足以破防,则防御力大于等于c[i].at+1的装备全部可以得到c[i].w的钱
		ans=max(ans,askmaxn(1,1,M,1,M)-ca[c[i].def+1]); 
		//防御力已经满足则只需要减去攻击力大于等于c[i].def+1的购买费用即可 
		//因为防御力已经排序了,所有后来的monster防御力一定大于先前的
		//当前选择的剑攻击力一定能破之前怪的防此时满足up的假设 故up函数成立 
	}
	printf("%lld",ans);
	return 0;
} 

  

这种是我最开始写的,因为inf 是int 类型(和上面代码开始犯的错一样)没过我还以为思路或者线段树写错了...结果没错

就是这个const long long inf=0xfffffffff坑死个人

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<set>
#include<list>
#include<vector>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
const int N=2e5+7;
const long long inf=0xfffffffff;
int n,m,p,pos1,pos2,pos3;
long long mat[N],mde[N],mv[N],de[N],ans=-inf;
bool use[N];
struct node 
{
	long long x,w,def;//atk==x?????def==x 
	bool operator <(const node &t)const{return x<t.x;}
}a[N],b[N],c[N];
struct node3
{
	long long sum,maxn,add;
}t[N*4];
long long max(long long x,long long y)
{
	if(x>y)
		return x;
	return y;
}
void built(int p,int l,int r)
{
	t[p].add=0;
	if(l==r)
	{
		t[p].maxn=-a[l].w;
		//t[p].sum=-b[l].w;
		return ;
	}
	int mid=(l+r)/2;
	built(p*2,l,mid);
	built(p*2+1,mid+1,r);
	t[p].maxn=max(t[p*2].maxn,t[p*2+1].maxn);
	//t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
void push_tag(int p,int l,int r)
{
	if(t[p].add)
	{
		t[p*2].add+=t[p].add;
		t[p*2+1].add+=t[p].add;
		t[p*2].maxn+=t[p].add;
		t[p*2+1].maxn+=t[p].add;
		t[p].add=0;
	}
	return ;
}
void push_down(int p)
{
	t[p].maxn=max(t[p*2].maxn,t[p*2+1].maxn);
}
void up(int p,int qx,int zx,int gl,int gr,int k)//???????? 
{
	if(qx>=gl&&zx<=gr)
	{
		t[p].add+=k;
		t[p].maxn+=k;
		return ;
	}
	int mid=(qx+zx)/2;
	push_tag(p,qx,zx);
	if(gl<=mid)
		up(p*2,qx,mid,gl,gr,k);
	if(gr>mid)
		up(p*2+1,mid+1,zx,gl,gr,k);
	push_down(p);
	return ;
}
 
long long askmaxn(int p,int qx,int zx,int gl,int gr)//??????? 
{
	if(qx>=gl&&zx<=gr)
	{
		return t[p].maxn;
	}
	int mid=(qx+zx)/2;
	long long ans=-inf;
	if(gl<=mid)	
		ans=max(ans,askmaxn(p*2,qx,mid,gl,gr));
	if(gr>mid)
		ans=max(ans,askmaxn(p*2+1,mid+1,zx,gl,gr));
	return ans;
}
int main()
{
	scanf("%d %d %d",&n,&m,&p);
	for(int i=1;i<=n;i++)
		scanf("%lld %lld",&a[i].x,&a[i].w);
	for(int i=1;i<=m;i++)
		scanf("%lld %lld",&b[i].x,&b[i].w);
	for(int i=1;i<=p;i++)
		scanf("%lld %lld %lld",&c[i].def,&c[i].x,&c[i].w);
	sort(a+1,a+n+1);
	sort(b+1,b+m+1);
	sort(c+1,c+p+1);//????????С???? 
	for(int i=1;i<=p;i++)
	{
		mat[i]=c[i].x;
		mv[i]=c[i].w;
		mde[i]=c[i].def;
	}
	for(int i=1;i<=n;i++)
		de[i]=a[i].x; 
	built(1,1,n);
	for(int i=1;i<=m;i++)
	{
		if(b[i].x>mat[p])
			pos2=p;
		else
			pos2=lower_bound(mat+1,mat+p+1,b[i].x)-mat-1;//???????????????? 
		for(int j=pos1+1;j<=pos2;j++)
		{
			//printf("#@$%d %d ",de[n],mde[j]);
			if(de[n]<=mde[j])
				continue;
			else
				pos3=upper_bound(de+1,de+n+1,mde[j])-de;//??????????????? 
			//printf("pos3=%d ", pos3);
			up(1,1,n,pos3,n,mv[j]);
			pos1=pos2;
		}
		ans=max(ans,askmaxn(1,1,n,1,n)-b[i].w);
		//printf("%lld ",askmaxn(1,1,n,1,n));
	}
	printf("%lld",ans);
	return 0;
} 

  

E题已经让我憔悴不堪,F题有生之年吧

有生之年的F题:

猜你喜欢

转载自www.cnblogs.com/cherrypill/p/12399072.html