Codeforces Round 677 (Div. 3) ABCDEFG题解

这篇博客分享了ACM竞赛中的几道算法题解,涉及A到G七道题目,包括数组操作、字符串处理、贪心策略、最短路径等算法思想。博主通过实例详细解析了每道题目的思路,如B题通过记录1之间的0个数求解,C题用贪心法找能吃掉所有数的数,E题计算特定排列的数量,F题运用线性DP解决棋盘问题,G题则讨论了最短路问题的变形。此外,博主还鼓励读者讨论和交流解题方法。
摘要由CSDN通过智能技术生成

呜呜,前两天晚上网炸了,错过了一波上分的机会,可能这次div3的题自己做着顺手吧,算是赛后补完了吧,(主要是F是最近刚在刷的线性dp,闫氏dp好,G题是个最短路思维题)

A题

题解:没啥好说的吧,一组是十位,然后分情况暴力就行了。

B题

思路:我的思路是记录下每个1和前一个1之间零的个数,然后求和,为什么这样想的呢?我们可以这样想,我们想让所有的1相邻,肯定是从第二个1开始往前移动吧,那我们可以想到,其实前面的1移动是不会影响后面1的相对位置的,即:我们移动第二个1,那么第三个1和第二个1相对位置是不会变的,而改变的只是第一个1和第二个1的相对位置。
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
			int n;
	cin>>n;
	int s[55];
	int ans=0;
	int res=0;
	for(int i=1;i<=n;i++)
	{
		cin>>s[i];
		if(s[i]) 
		{
			if(res==0) res=i;
			else
			{
				ans+=i-res-1;
				res=i;
			}
		}
	}
	cout<<ans<<endl;
	}

 } 

C题

题目大意:就是给了一系列的数,如果一个数大于它左边或右边的数,它就可以吃掉这个数,然后自身加1,问能不能找出一个数把除它以为所有的数都吃掉。

思路:很好分析的一点,只有当所有数相等的时候才找不到这样的数,其他情况都可以找到这样的数,并且这样的数大部分情况是不唯一的,我们可以用贪心法找,找到数组里最大的数,并且要求他的左右两边至少有一个数小于它,对于数组中的最大数来说这个数是肯定能找到了(因为我们已经排除了每个数都相等的情况)。
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
long long  s[N];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
			int n;
	cin>>n;
	bool jud=true;
	long long res=0;
	long long idx=1;
	for(int i=1;i<=n;i++)
	{
		cin>>s[i];
		if(i==1) res=s[i];
		else
		{
			if(res!=s[i]) jud=false;
			if(s[i]>s[idx]) idx=i;
		}
	}
	if(jud) cout<<-1<<endl;
	else 
	{
		for(int i=1;i<=n;i++)
		{
			if(i==1)
			{
				if(s[i]==s[idx] && s[i+1]!=s[idx])
				{
					cout<<i<<endl;
					break;
				}
			}
			else if(i==n)
			{
				if(s[i]==s[idx] && s[i-1]!=s[idx])
				{
					cout<<i<<endl;
					break;
				}
			}
			else
			{
				if(s[i]==s[idx] && (s[i-1]!=s[idx] || s[i+1]!=s[idx]))
				{
					cout<<i<<endl;
					break;
				}
			}
		}
	}
	}

 } 

D题

题目大意:大概意思就是有n个城市,然后每个城市有一个黑帮分部emmm大概就是这样,我们需要让n个城市连通,但是又不能让两个同属一个分部的黑帮直接相连,问我们能不能达到要求,如果可以的话输出我们连的道路
思路:首先我们先分析怎么样就能达成要求呢?显然的,连接n个城市需要n-1条道路,然后n个城市我们有n*(n-1)/2条路可选,然后呢如果有m个城市 属于同一个黑帮那么他们之间的m*(m-1)/2条路就不能选了,只要我们减去每个黑帮里属于同一黑帮而不能选的路最后剩下的路大于等于n-1条路就能达到要求了
  最后一点就是我们如何输出道路呢?很简单啦,我们只需要找到两个属于不同黑帮城市的下表,然后让其中一个与所有和另一个属于同一黑帮的城市相连,而另一个和其他所有城市相连即可。
#include<bits/stdc++.h>
using namespace std;
int t;
const int N=5001;
long long a[N],b[N];
bool ma[N][N];
int main()
{
	cin>>t;
	while(t--)
	{
 
		int n;
		cin>>n;
		int lk,kl;
		for(int i=1;i<=n;i++)
		{
		    cin>>a[i];
		    if(i==1)  lk=a[1];
		    else if(lk!=a[i]) kl=i;
		    b[i]=a[i];
		}
	    sort(b+1,b+n+1);
	    long long z=1;
	    long long jud=b[1];
	    long long ans=0;
	    for(int i=2;i<=n;i++)
	    {
	    	if(b[i]==jud)
	    	{
	    		z++;
			}
			else
			{
				if(z>1) ans+=z*(z-1)/2;
				z=1;
				jud=b[i];
			}
		}
			if(z>1) ans+=z*(z-1)/2;
		if(ans>n*(n-1)/2-n+1) cout<<"NO"<<endl;
		else
		{
			cout<<"YES"<<endl;
			int h=0;
			for(int i=2;i<=n;i++)
			{
				if(a[i]!=a[1]) cout<<1<<' '<<i<<endl;
				else cout<<kl<<' '<<i<<endl;
			}
		}
 
	    
	}
E题
题解:emmmm,圆舞曲??反正就是分组啦,然后其实我做的时候是找的规律,首先考虑一点,题目中也说了,我们分组的话,每一组其实是没有排头的概念的,什么意思呢?就是说比如 1234和2341是一样的,那么我的思路就是 我只找1开头的,那么对于n来说,就是(n-1)!,然后我们还要除以一个(n/2),当然长度是1的时候就别除了。
#include<bits/stdc++.h>
using namespace std;
int main()
{
	long long n;
	cin>>n;
	long long x=1;
	for(int i=1;i<=n-1;i++)
	x*=i;
	if(x>2) x/=(n/2);
	cout<<x<<endl;
}
F题
题解:先说思路 我用的是四维dp,由于这道题数据范围很小不会超时,建议大家也可以再看看别人的题解,因为这道题用四维dp的话应该可以说是最朴素的了,其他大佬应该有优化的手段吧,我用的是闫氏dp分析法,(给acwing打波广告,y总yyds),注意一点的是这里我加了一个dp[i][0][0][m],我用它来记录每行不选时各个余数对应的最大值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=71;
int ma[N][N],dp[N][N][N][N];
int n,m,k;
int main()
{
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>ma[i][j];
		}
	}
	memset(dp,-1,sizeof dp);
	dp[1][0][0][0]=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			for(int z=0;z<=min(j,m/2);z++)
			{
				for(int h=0;h<k;h++)
				{
				      int l=ma[i][j]%k;
				      dp[i][j][z][h]=dp[i][j-1][z][h];
				      if(z>0)
				      {
				      	if(l>h)
				      {
				      	int o=h+k;
				      	if(dp[i][j-1][z-1][o-l]!=-1)
				      	{
				      		dp[i][j][z][h]=max(dp[i][j][z][h],dp[i][j-1][z-1][o-l]+ma[i][j]);
						  }
					  }
					  else
					  {
					  	if(dp[i][j-1][z-1][h-l]!=-1)
					  	dp[i][j][z][h]=max(dp[i][j][z][h],dp[i][j-1][z-1][h-l]+ma[i][j]);
					  }
					  }
				      
	               if(j==m)  dp[i+1][0][0][h]=max(dp[i+1][0][0][h],dp[i][j][z][h]);
				}
				
			}
		}
	}
	cout<<dp[n+1][0][0][0]<<endl;
}
题解:比普通的最短路问题多了一点就是形成了最短路之后,让我们求如果我们可以把任意两点之间距离变为0,我们最少可以得到的最短路是多少,其实很简单了,比如我们把a,b两点距离变为0,然后我们求n,m两点距离只要求dist[n][m],dist[n][a]+dist[b][m],dist[n][b]+dist[a][m]三个的最小值。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1005;
const int maxn=N*N/2;
int dist[N][N];
int map[N][N];
int bian[N][N];
int n,m,z;
struct node{
	int a;
	int b;
}nodes[1005];
struct node1
{
	int a1;
	int b1;
	int w;
}nodes1[maxn];
int main()
{
	cin>>n>>m>>z;
	memset(dist,0x3f,sizeof dist);
	for(int i=1;i<N;i++)
	dist[i][i]=0;
	for(int i=1;i<=m;i++)
	{
		int a,b,w;
		cin>>a>>b>>w;
		nodes1[i].a1=a;
		nodes1[i].b1=b;
		nodes1[i].w=w;
		dist[a][b]=dist[b][a]=min(dist[a][b],w);
	}
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
			}
		}
	}
	for(int i=1;i<=z;i++)
	{
		cin>>nodes[i].a>>nodes[i].b;
	}
	int ans=0x3f3f3f3f;
	for(int i=1;i<=m;i++)
	{
		int sum=0;
		node1 node2=nodes1[i];
		for(int j=1;j<=z;j++)
		{
			int minl=min(dist[nodes[j].a][nodes1[i].a1]+dist[nodes1[i].b1][nodes[j].b],dist[nodes[j].a][nodes1[i].b1]+dist[nodes1[i].a1][nodes[j].b]);
			sum+=min(dist[nodes[j].a][nodes[j].b],minl);
		}
		ans=min(ans,sum);
	}
	cout<<ans<<endl;
}
可能有的地方说的不清楚,欢迎和我讨论

.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值