SDNU2020寒假训练赛1题解+补题

题目链接

C*Planning

题意:有n个飞机,第i个飞机第i分钟起飞,延误一分钟损失v[i]。
现因不可抗力,前k分钟不能起飞。求一种起飞顺序方案,使总损失最低。

思路:贪心。
总损失=∑(i-a[i].id)*a[i].v=∑(i *a[i].v)-∑(a[i].id *a[i].v)
而后面的∑(a[i].id *a[i].v)是固定已知的,所以只需要∑(i *a[i].v)最小即可。
贪心方法是按a[i].v,用大根堆维护,每次取堆顶飞机起飞。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
#include<math.h>
#include<vector>
using namespace std;
#define Inf 0x7fffffff
typedef long long ll;
const int N=300007;
ll ans;
struct node{
	ll id,v;
	bool operator <(const node &o)const{
		return v<o.v;
	}
}a[N];
int n,k,order[N];
priority_queue<node>q;
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i].v);
		a[i].id=i;
	}
	for(int i=1;i<=k;i++)q.push(a[i]);
	for(int i=k+1;i<=k+n;i++){
		if(i<=n)q.push(a[i]);
		node t=q.top();q.pop();
		ans+=(i-t.id)*t.v;
		order[t.id]=i;
	}
	cout<<ans<<endl;
	for(int i=1;i<=n;i++)printf("%d ",order[i]);
}

F*Thor

题意:按照时间顺序发生q次三种事件:
1.编号x的app收到了一条信息
2.看完编号x的app的所有信息
3.看完从第一条信息开始计数的前k条信息(不是前k条未读信息,而是前k条信息)。
在每次事件结束之后输出一次当前总的未读信息数

思路:给每个app开一个队列维护,1进队,2清空队列,3判断队首是否出队。
每个元素最多进队一次出队一次,所以复杂度O(q)

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
#include<math.h>
#include<vector>
using namespace std;
#define Inf 0x7fffffff
typedef long long ll;
const int N=300007;
int n,q,all,cnt,note[N],pre;
deque<int>a[N];

int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n>>q;
	int opt,t;
	for(int i=1;i<=q;i++){
		scanf("%d%d",&opt,&t);
		if(opt==1){
			a[t].push_back(++cnt);
			note[cnt]=t;
			all++;
		}else 
		if(opt==2){
			if(a[t].size()){
				all-=a[t].size();
				a[t].clear();
			}
		}else
			if(t>--pre){
				while(++pre<=t){
					if(!a[note[pre]].size())continue;
					int now=a[note[pre]].front();
					if(now<=t){
						a[note[pre]].pop_front();
						all--;
					}
				}
			}
		cout<<all<<"\n";
	}
}
				
			

G.Hard problem

题意:给n个小写字母字符串,使第i个串反转的代价为c[i],可以选择使任意串反转或不反转。求使1~n个字符串按原顺序是字典序升序排列的反转方案的最小代价。

思路:预处理s[i]反转后的字符串ss[i],dp
设f[i][0]为第i串不反转的最小代价,f[i][1]为第i串反转的最小代价,皆可由f[i-1][0]和f[i-1][1]推出来。(!要初始化f数组为Inf)
结果是min(f[n][0],f[n][1])

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
#include<math.h>
#include<vector>
using namespace std;
#define Inf 100000000000000000
typedef long long ll;
const int N=100007;
string s[N],ss[N];
ll c[N],f[N][2];
int n;

int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>c[i];
	for(int i=1;i<=n;i++){
		cin>>s[i];
		int l=s[i].length();
		for(int j=0;j<l;j++)ss[i]+=s[i][l-j-1];
		f[i][0]=f[i][1]=Inf;
	}
	f[1][0]=0;f[1][1]=c[1];
	for(int i=2;i<=n;i++){
		if(s[i]>=s[i-1])f[i][0]=f[i-1][0];
		if(s[i]>=ss[i-1])f[i][0]=min(f[i][0],f[i-1][1]);
		if(ss[i]>=s[i-1])f[i][1]=f[i-1][0]+c[i];
		if(ss[i]>=ss[i-1])f[i][1]=min(f[i][1],f[i-1][1]+c[i]);
	}
	ll ans=min(f[n][0],f[n][1]);
	if(ans==Inf)cout<<-1;else cout<<ans;
}
发布了17 篇原创文章 · 获赞 7 · 访问量 2025

猜你喜欢

转载自blog.csdn.net/qq_45530271/article/details/104079887