2021.10.11 提高组模拟

总的来说考得一般般……100+10+85+10,就那样。

T1 a

题意:

给定一个长度为 \(N(N\le 10^7)\) 的仅包含小写字母的字符串。请你求出其字典序最大的子序列。

解法

题解是什么不重要,反正我的玄学方法能过就行了。我的做法是先把所有的字符z找出来输出,再找y,依次下去,然而这个带常数的做法目前为止还是最优解

#include<cstdio>
//#define zczc
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
    wh*=f;return;
}

int m,sum[30];
char w;

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);
	w=getchar();
	while(w<'a'||w>'z')w=getchar();
	sum[w-'a']++;
	for(int i=2;i<=m;i++){
		w=getchar();
		sum[w-'a']++;
		for(int j=w-'a'-1;j>=0;j--)sum[j]=0;
	}
	for(int i=25;i>=0;i--){
		while(sum[i]--)putchar(i+'a');
	}
	
	return 0;
}

T2 b

题意

给定一个长度为 \(N(N\le 5\times 10^6)\) 的序列。删除其中的一个元素需要花费的代价是其本身乘上与其相邻的
元素的乘积。请你求出将该序列删空的最小代价。

解法

首先我想到的是什么区间DP,但是没写出来;后来想到一个似乎是绝妙的优化,那就是每次删除只会删除左端点或者右端点,这样一定是最优的,因为这样一来,每次的代价就会是两个数相乘,而不是三个数连乘。

于是考试时打了个奇怪的线性DP,交上去,只有20分,实在不应该。

后来看了解法,发现是因为没有考虑到一些情况,比如对于序列 1 2 1,它的最优解就是先删中间再删两边,答案为4 。为什么会造成这一情况呢,不是因为结论有问题,而是因为那个“两数乘积小于三数乘积”的结论在这三个数中有1时不再适用。于是用题解的话说,就是以1为分界把原序列割裂成许多小段,对每个小段用上面的结论快速求解。

由数据规模可知,对于每个小段应用 \(O(N)\) 的复杂度求解。发现按照上面那个方法可以得知,对于一个序列,先删最左边再删最右边与先删最右边再删最左边是一个效果,也就是说不论按照什么顺序删,代价都是一样的。这就符合线性求解的特征。

然后就可以了。最后说一下,由于每个序列删完之后最后会剩下一个元素,秉着贪心的原则,就选择每一段中最小的那个元素,累加它即可。

#include<cstdio>
#define int long long
const int N=5000010;
int m,ans,minn=1e18,a[N];

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	scanf("%lld",&m);
	for(int i=1;i<=m;i++){
		scanf("%lld",&a[i]);
		if(a[i]==1)ans++;
	}
	int l=1,r=1;
	while(l<m){
	    while(l<=m&&a[l]==1)l++;r=l;
		while(r<=m&&a[r]!=1)r++;r--;
		for(int i=l;i<=r;i++)minn=minn>a[i]?a[i]:minn;
		for(int i=l+1;i<=r;i++)ans+=a[i]*a[i-1];
		ans+=minn;minn=1e18;l=r+1;
	}
	printf("%lld",ans);
	
	return 0;
}

T3 c

题意

给定一张 N 个点 M 条边且边带权的无向图,你可以选择任意一条 S 到 T 之间的最短路径,使得这条路径上的所有边权变为 0。求出进行修改之后,X 到 Y 之间路径长度的可能的最小值是多少。Q 次询问。

\(N,M\le 10^5,Q\le 10\)

解法

暴力枚举即可,复杂度很假,但由于数据过水可以卡过。仅供参考。正解是建最短路图(建出来是个DAG)再进行拓扑DP,但我没写。

#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
//#define zczc
#define ll long long
#define int long long
using namespace std;
const int N=100010;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
    wh*=f;return;
}

int m,n,r,l,s,t;
struct edge{
	int t,v,next;
}e[N<<4];
int esum,head[N];
inline void add(int fr,int to,int val){
	esum++;
	e[esum].t=to;
	e[esum].v=val;
	e[esum].next=head[fr];
	head[fr]=esum;
	return;
}

vector<int>mem[N];
ll dis[N];
bool vis[N];
struct node{
	int wh;ll dis;
};
bool operator <(node s1,node s2){
	return s2.dis<s1.dis;
}
priority_queue<node>q;

int st[N],top;
int phead[N];
ll ans=1e18;
void check(){
	int pesum=esum;
	for(int i=1;i<=m;i++)phead[i]=head[i];
	for(int i=2;i<=top;i++){
		add(st[i],st[i-1],0);
		add(st[i-1],st[i],0);
	}
	memset(dis,0x3f,sizeof(dis));
	memset(vis,false,sizeof(vis));
	dis[s]=0;
	q.push((node){s,0});
	while(!q.empty()){
		int wh=q.top().wh;ll nd=q.top().dis;q.pop();
		if(vis[wh])continue;vis[wh]=true;
		for(int i=head[wh],th;i;i=e[i].next){
			th=e[i].t;
			if(dis[wh]+e[i].v<dis[th]){
				dis[th]=dis[wh]+e[i].v;
				q.push((node){th,dis[th]});
			}
		}
	}
	//for(int i=1;i<=top;i++)printf("%lld ",st[i]);printf("\n");
	if(dis[t]<ans)ans=dis[t];
	esum=pesum;
	for(int i=1;i<=m;i++)head[i]=phead[i];
	return;
}
void dfs(int wh){
	st[++top]=wh;
	if(wh==l){
		check();
		return;
	}
	for(int i=0;i<mem[wh].size();i++){
		dfs(mem[wh][i]);
	}
	top--;
	return;
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(n);
	read(l);read(r);
	read(s);read(t);
	int s1,s2,s3;
	for(int i=1;i<=n;i++){
		read(s1);read(s2);read(s3);
		add(s1,s2,s3);add(s2,s1,s3);
	}
	
	memset(dis,0x3f,sizeof(dis));
	dis[l]=0;
	q.push((node){l,0});
	while(!q.empty()){
		int wh=q.top().wh;ll nd=q.top().dis;q.pop();
		if(vis[wh])continue;vis[wh]=true;
		for(int i=head[wh],th;i;i=e[i].next){
			th=e[i].t;
			if(dis[wh]+e[i].v<dis[th]){
				mem[th].clear();
				mem[th].push_back(wh);
				dis[th]=dis[wh]+e[i].v;
				q.push((node){th,dis[th]});
			}
			else if(dis[wh]+e[i].v==dis[th]){
				mem[th].push_back(wh);
			}
		}
	}
	dfs(r);
	printf("%lld",ans);
	
	return 0;
}
posted @ 2021-10-14 13:44  Feyn618  阅读(38)  评论(0编辑  收藏  举报