AtCoder Beginner Contest 252

AtCoder Beginner Contest 252

D

题意

在数组中形如 \(1\leq i<j<k\leq n\)使得\(a_i,a_j,a_k\)互不相同,求共有多少组满足条件

思路

它的数据范围\(1\leq a_i\leq 2*10^5\),这就用个数组求个前缀和就搞定了。

代码

void solve() 
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i],cnt[a[i]]++;
	int ans=0;
	for(int i=1;i<N;i++) sum[i]=sum[i-1]+cnt[i];
	for(int i=1;i<N;i++) 
	{
		ans+=cnt[i]*sum[i-1]*(sum[N-1]-sum[i]);
	}
	cout<<ans<<endl;
}

E (最短路)

题意

给个n个节点m条边的图,问把最短路弄出来后需要保留哪些边。

思路

dijkstra 求一遍,加个参数表示当前边的序号,表示在最短路中当前结点和父节点是通过该条边连接的。
这题最大的收获不是复习这个最短路,而是发现了memset不能赋值
1e18,以后还是用fill初始化吧

代码

void add(int a,int b,int c,int i) 
{
	e[idx]=b;
	w[idx]=c;
	id[idx]=i;
	ne[idx]=h[a];
	h[a]=idx++;
}

void dijk() 
{
	memset(dis,inf,sizeof(dis));
	dis[1]=0;
	priority_queue<pii> q;
	q.push({0,1});
	while(q.size()) 
	{
		pii tmp = q.top();
		int u=tmp.second;
		q.pop() ;
		if(vis[u]) continue;
		vis[u]=true;
		for(int i=h[u];i!=-1;i=ne[i]) 
		{
			int j=e[i];
			if(dis[j]>dis[u]+w[i]) 
			{
				dis[j]=dis[u]+w[i];
				q.push({-dis[j],j});
				use[j]=id[i];
			}
		}
	}
}

void solve() 
{	
	memset(h,-1,sizeof(h));
	cin>>n>>m;
	for(int i=1;i<=m;i++) 
	{
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c,i);
		add(b,a,c,i);
	}
	dijk();
	for(int i=2;i<=n;i++) cout<<use[i]<<" ";
	cout<<endl;
}

F

题意

一块长为L的面包,然后有n个小朋友,每个人要吃\(A_i\)长度的面包,将一块长为x的面包切一下需要花费x,这块面包就变成x-k和k了。问最少花费多少来满足小朋友的要求,面包可以有剩下。

思路

经典枯坐半小时, 还是灰溜溜看题解
逆向思维。贪心地想,一块面包肯定是从一块长度大于它且是最短的面包中切出来的,所以这块面包应该和其他面包中最短的那个组合起来的,这样是最优解。

代码

void solve() 
{
	cin>>n>>m;
	priority_queue<int> q;
	int sum=0;
	for(int i=1;i<=n;i++) 
	{
		int x;
		cin>>x;
		q.push(-x);
		sum+=x;
	} 
	if(m-sum>0) q.push(sum-m);
	int ans=0;
	while(q.size()>1) 
	{
		int x1=q.top();q.pop();
		int x2=q.top();q.pop();
		ans-=x1+x2;
		q.push(x1+x2);
	}
	cout<<ans<<endl;
}

车到山前必有路,而且有两条,一条是回去的路,而另一条,是上山的路

posted @ 2023-03-04 18:49  Liang2003  阅读(15)  评论(0编辑  收藏  举报