noip模擬21

ccjjxx發表於2024-11-26

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 彩燈晚會