noip模拟21

A 打印

一眼题。

首先一个很简单的思路就是维护一个打印机的优先队列,按照打印机的时间排序。

但是如果现在可用的打印机有很多,你需要找到一个 id 最小的,这样维护就得把所有时间戳小于当前 \(t_i\) 的打印机全部弹出,统计,再加回来。有 60 分。

然后就能想到把时间戳小于等于当前的和大于当前的打印机分别维护,因为打印序列递增,时间递增,所以每次加进来的打印任务直接弹上次在大于时间戳范围的队头,加入到当前可用的队列中。

当前可用的队列用 id 排序,大于时间戳的队列用时间和 id 双关键字排序。

每次计算完答案把这个打印机加入大于时间戳的队列即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
const int N=2e5+5;
struct node{
	int s,t,id;
}a[N<<1];
struct printers{
	int tim,id;
	inline bool operator<(const printers &ll) const 
	{
//		if(tim==ll.tim) return id>ll.id;
		return id>ll.id;
	}
};
struct pRinters{
	int tim,id;
	inline bool operator<(const pRinters &ll) const 
	{
		if(tim==ll.tim) return id>ll.id;
		return tim>ll.tim;
	}
};

priority_queue<printers>q;
priority_queue<pRinters>tmp;
vector<int>ans[N];
inline bool cmp(node a,node b)
{
	if(a.t==b.t) return a.s<b.s;
	return a.t<b.t;
}
void print()
{
	for(int i=1;i<=m;i++) 
	{
		cout<<ans[i].size();
		sort(ans[i].begin(),ans[i].end());
		int siz=ans[i].size();
		if(siz) cout<<" ";
		for(int j=0;j<siz-1;j++) cout<<ans[i][j]<<" ";
		if(siz)
		cout<<ans[i][siz-1];
		cout<<"\n";
	}
}
signed main()
{
	freopen("print.in","r",stdin);
	freopen("print.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i].s>>a[i].t,a[i].id=i;
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=m;i++) q.push({0,i});
	for(int i=1;i<=n;i++)
	{
		while(!tmp.empty()&&tmp.top().tim<=a[i].t) q.push({tmp.top().tim,tmp.top().id}),tmp.pop();
		if(!q.empty())
		{
			int tim=q.top().tim,id=q.top().id;q.pop();
			ans[id].push_back(a[i].id);
			tmp.push({a[i].t+a[i].s,id});
		}
		else
		{
			int tim=tmp.top().tim,id=tmp.top().id;tmp.pop();
			ans[id].push_back(a[i].id);
			tmp.push({tim+a[i].s,id});
		}
	}
	print();
	
}

B 飞船

有一个很一眼的 dp,设 \(dp[i][j]\) 表示到第 \(i\) 个加油站,速度为 \(j\) 的最小花费,转移就从 \(dp[i-1][j]\)\(dp[i-1][j/x_i]\) 分别转移即可。

然后发现速度其实是很多个 \(2\)\(3\) 的连乘,于是写成指数的形式,并把操作离线,把每个询问当作一个啥都干不了的加油站,然后转移。时间复杂度 \(O((n+m)\log n)\) 左右。

点击查看代码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,q;
const int N=2e5+5;
const double exps=1e-10,inf=1e18;
int dis[N],t[N],id[N];
int y;
vector<int>A;
const int M=31,K=19;
double dp[2][32][20];
int nowdis[N],nowt[N],nowid[N];
struct node{
	int dis,t,id,ansid;
}a[N];
int ansid[N];
inline bool cmp(node a,node b)
{
	return a.dis<b.dis;
}
double pow2[32],pow3[20];
double ans[N];
int dd[N];
inline double min(double a,double b)
{
	if(a-b>exps) return b;
	return a;
}
inline double calc(double dis,int x,int y){
	if(dis<exps)return 0.0;
	if(dis<exps*pow3[y])return 0.0;
	dis/=pow3[y];
	if(dis<exps*pow2[x])return 0.0;
	dis/=pow2[x];
	return dis;
}
signed main()
{
//	freopen("b.in","r",stdin);
	freopen("ship.in","r",stdin);
	freopen("ship.out","w",stdout);
	scanf("%lld%lld",&n,&q);
	bool allxIs1=1,allxIs12=1;
	for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&dis[i],&t[i],&id[i]),allxIs1&=(id[i]==1);
	if(allxIs1)
	{
		while(q--)
		{
			scanf("%lld",&y);
			long double ans=1.0*y;
			printf("%.20Lf\n",ans);
		}
		return 0;
	}
	pow2[0]=pow3[0]=1.0;
	for(int i=1;i<=M;i++) pow2[i]=pow2[i-1]*2.0;
	for(int i=1;i<=K;i++) pow3[i]=pow3[i-1]*3.0;
	for(int i=1;i<=n;i++) if(id[i]>1) A.push_back(i);
	int cc=0; 
	for(int v:A) nowdis[++cc]=dis[v],nowt[cc]=t[v],nowid[cc]=id[v];
	for(int i=1;i<=cc;i++) dis[i]=nowdis[i],t[i]=nowt[i],id[i]=nowid[i];
	n=cc;
	int tmp=n;
	for(int i=1;i<=q;i++)
	{
		scanf("%lld",&y);
		dis[++tmp]=y,t[tmp]=0,id[tmp]=1,ansid[tmp]=i;
	}
	n=tmp;
	for(int i=1;i<=n;i++) a[i].dis=dis[i],a[i].id=id[i],a[i].t=t[i],a[i].ansid=ansid[i];
	sort(a+1,a+1+n,cmp);
	int r=0;
	for(int i=0;i<=M;i++)
		for(int j=0;j<=K;j++) dp[0][i][j]=dp[1][i][j]=inf;
	dp[0][0][0]=0;
	int _2lim=0,_3lim=0;
	for(int i=1;i<=n;i++)
	{
		double d=(double)(a[i].dis-a[i-1].dis);
		r^=1;
		if(a[i].id==2)++_2lim;
		if(a[i].id==3)++_3lim;
		if(a[i].id==4)_2lim+=2;
		int JL=min(_2lim,M-1ll),KL=min(_3lim,K-1ll);
		for(int j=0;j<=JL;j++)
			for(int k=0;k<=KL;k++) dp[r][j][k]=inf;
		for(int j=0;j<=JL;j++)
		{
			for(int k=0;k<=KL;k++)
			{
				if(a[i].id==2&&j>0&&dp[r^1][j-1][k]!=(double)inf) dp[r][j][k]=min(dp[r][j][k],dp[r^1][j-1][k]+calc(d,j-1,k)+a[i].t);
				if(a[i].id==3&&k>0&&dp[r^1][j][k-1]!=(double)inf) dp[r][j][k]=min(dp[r][j][k],dp[r^1][j][k-1]+calc(d,j,k-1)+a[i].t);
				if(a[i].id==4&&j>1&&dp[r^1][j-2][k]!=(double)inf) dp[r][j][k]=min(dp[r][j][k],dp[r^1][j-2][k]+calc(d,j-2,k)+a[i].t);
				if(dp[r^1][j][k]==(double)inf) continue;
				dp[r][j][k]=min(dp[r][j][k],dp[r^1][j][k]+calc(d,j,k));
			}
		}
		if(a[i].ansid)
		{
			ans[a[i].ansid]=inf;
			for(int j=0;j<=JL;j++)
			{
				for(int k=0;k<=KL;k++)
					if(ans[a[i].ansid]-dp[r][j][k]>exps) ans[a[i].ansid]=dp[r][j][k];
			}
		}
	}
	for(int i=1;i<=q;i++) printf("%.20lf\n",ans[i]);
}

C 简单的字符串问题 2

D 彩灯晚会

posted @ 2024-11-26 23:21  ccjjxx  阅读(9)  评论(0编辑  收藏  举报