NIYAXIMEN

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  13 随笔 :: 0 文章 :: 0 评论 :: 238 阅读

Educational Codeforces Round 165

Problem - A - Codeforces

答案只会是2或3,分类一下就好了

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n;
int a[N];
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	if(n==2)
	{
		cout<<"2"<<endl;
	}
	else
	{
		for(int i=1;i<=n;i++)
		{
			if(i==a[a[i]])
			{
				cout<<"2"<<endl;return ;
			}
		}
		cout<<"3"<<endl;
	}
	
}
int main()
{
	int t;cin>>t;
	while(t--)solve();
}

Problem - B - Codeforces

找规律,对于初始前面有\(1\)\(0\),一定要移动到前面去,最小代价是它前面\(1\)的个数再加\(1\)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n;
int a[N];
void solve()
{
	string s;cin>>s;
	long long cnt=0,ans=0;
	for(int i=0;i<s.length();i++)
	{
		if(s[i]=='1')cnt++;
		else
		{
			if(cnt)
			ans+=(1+cnt);
		}
	}
	cout<<ans<<endl;
}
int main()
{
	int t;cin>>t;
	while(t--)solve();
}

Problem - C - Codeforces

DP

没想出来...

对于一个\(dp\)问题的状态划分应该满足:

1.转移方程便于求解

2.最后答案包含在可以计算的状态里

来看这个问题,进行一次操作可以使\(a_i\)变成相邻的数,最多进行\(k(k\leq 10)\)次操作,求数组\(sum\)的最小值

看到\(k\)的范围很明显想到\(dp\)问题

刚开始我定义\(dp[i][j]\)是前\(i\)项,用了不多于\(j\)次操作的最小总和,但是发现这样是有问题的,因为\(a[i]\)也可能由后面的元素变化而来,这样的话状态计算会很复杂,所以要避免这样划分

重新定义\(dp[i][j]\)是前\(i\)项,对前\(i\)项用不多于\(j\)次操作的最小总和,这样免去了对后缀的讨论,且最终状态\(dp[n][k]\)的含义也符合要求。

然后就是状态转移的计算了

假设遍历到\(i\),如果有\(d\)次操作,最多可以使\(i\)扩展到\(i-d\),此时的答案便是

\[dp[i-d-1][j-d]+(d+1)*mi\\ mi=min(a_p)\ i-d\leq p\leq i \]

因此状态转移方程就是

\[dp[i][j]=min(dp[i-d-1][j-d]+(d+1)*mi)\\ 0\leq d \leq j \]

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n,k;
long long dp[N][12];
int a[N];
void solve()
{
    scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		dp[i][0]=dp[i-1][0]+a[i];
	}
	a[n+1]=2e9;a[0]=2e9;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=k;j++)
		{
			int mi=a[i];dp[i][j]=dp[i-1][j]+a[i];//先前没有初始化,所以此处先赋个初始值
			for(int len=0;len<=j&&i-len>=1;len++)//注意边界
			{
				mi=min(mi,a[i-len]);
				dp[i][j]=min(dp[i-1-len][j-len]+1LL*(len+1)*mi,dp[i][j]);
			}
		}
	}
	cout<<dp[n][k]<<endl;
}
int main()
{
	int t;cin>>t;
	while(t--)solve();
}

Problem - D - Codeforces

博弈 排序

\(Alice\)先选择地买东西,\(Bob\)再从\(Alice\)手上买

\(Bob\)可以至多从\(Alice\)手上零元购\(k\)个物品

利润为\(Alice\)花的钱减去卖的钱,\(Alice\)要最大化利润,\(Bob\)要最小化

对于一件物品\(i\)

A不选,利润为\(0\)

A选了,B不选,利润为\(b[i]-a[i]\)

AB都选了,利润为\(-a[i]\)

可以看出,对于一件A买了的物品,若B选择且零元购的话,可以使得A损失\(-a[i]-(b[i]-a[i])=-b[i]\)

因此B应该要优先选择\(b[i]\)大的物品

而对于A而言,他选择的前\(k\)大的物品是肯定不赚钱的,会亏损\(\sum a\),所以A要使选择的前\(k\)个物品的\(\sum a_i\)最小

先将数组按照\(b_i\)降序排序,枚举分界点,对于分界点左边的都是B选择的或者是A不选的,右边则只要选择\(b_i>a_i\)即可

用一个大根堆来维护\(a_i\),先把前\(k\)个元素的\(a_i\)入堆,然后向后遍历,如果遇到\(a_i<top\)的,则将\(top\)出队,将\(a_i\)入队

\(suf[i]=\sum_{i\leq k\leq n}max(0,b_k-a_k)\),最多的正利润便是\(suf[k+1]\),因此从\(k+1\)遍历到\(n\),包括了所有情况

#include<bits/stdc++.h>
using namespace std;
typedef pair<long long,long long>pii;
const int N=2e5+10;
int n,k;
pii a[N];
long long pre[N];
bool cmp(pii a,pii b)
{
	return a.second>b.second;
}
void solve()
{
    scanf("%d%d",&n,&k);long long res=0,ans=0;priority_queue<long long>heap;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i].first);
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i].second);
	}
	sort(a+1,a+1+n,cmp);pre[n+1]=0;
	for(int i=n;i>=1;i--)
	{
		pre[i]=pre[i+1]+max(a[i].second-a[i].first,0LL);
	}
	long long ze=0;
	for(int i=1;i<=k;i++)
	{
		ze+=a[i].first;
		heap.push(a[i].first);
	}
	for(int i=k+1;i<=n;i++)
	{
		res=pre[i]-ze;ans=max(ans,res);
		if(heap.size())
		{
			if(a[i].first<heap.top())
			{
				ze=ze+a[i].first-heap.top();
				heap.pop();heap.push(a[i].first);
			}
		}
	}
	cout<<ans<<endl;
}
int main()
{
	int t;cin>>t;
	while(t--)solve();
}
posted on   AsukaAlice  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示