Codeforces Round #642 (Div. 3) A-F题解

比赛地址
A.Most Unstable Array
思路:显然 0 m 0 这样放是最大的

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int t,n,m;
int main() {
  ios::sync_with_stdio(false);
  for(cin>>t;t;t--){
  	cin>>n>>m;
  	if(n==1)cout<<0<<endl;
  	else {
  		if(n==2){
  			cout<<m<<'\n';
  		}else cout<<2*m<<'\n';
  	}
  }
 	return 0;
}

B.Two Arrays And Swaps
思路:把a,b排序,显然 最大的值必然是a的一个后缀 加上b的一个后缀,枚举即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int t,n,k,a[N],b[N];
int s[N],q[N];
int main() {
  ios::sync_with_stdio(false);
  for(cin>>t;t;t--){
  	cin>>n>>k;
  	for(int i=1;i<=n;i++){
  		cin>>a[i];
  	}
  	for(int j=1;j<=n;j++){
  		cin>>b[j];
  	}
  	sort(a+1,a+1+n);
  	sort(b+1,b+1+n);
  	for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i],q[i]=q[i-1]+b[i];
  	int ans=s[n];
  	for(int i=1;i<=k;i++){
  		ans=max(ans,s[n]-s[i]+q[n]-q[n-i]);
  	}
  	cout<<ans<<'\n';
  }
 	return 0;
}

C.Board Moves
思路:
首先考虑一下暴力的代码:

int dx=(n+1)/2;
for(int i=1;i<=n;i++){
	for(int j=1;j<=n;j++){
		int x=abs(i-dx),y=abs(j-dx);
		ans+=x+y-min(x,y);
	}
}

那么观察这个式子,我们可以通过枚举x,将y进行分段 [ 1 , x ] , [ x + 1 , n / 2 ] [1,x],[x+1,n/2] [1,x],[x+1,n/2]进行求和即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int t,n;
int main() {
  ios::sync_with_stdio(false);
  for(cin>>t;t;t--){
  	cin>>n;
  	LL ans=0;
  	if(n==1){
  		cout<<0<<'\n';
  		continue;
  	}
  	for(int i=1;i<=n/2;i++){
  		int x=(n+1)/2-i;
  		LL cnt=1ll*(1+n/2)*(n/2)/2;
  		cnt-=1ll*(n/2-x)*x+1ll*(1+x)*x/2;
  		ans+=2*cnt;
  		ans+=1ll*x*n;
  	}
  	ans=ans*2+1ll*(1+n/2)*(n/2);
  	cout<<ans<<'\n';
  }
 	return 0;
}

D.Constructing the Array
思路:set模拟题意即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int t,n,a[N];
struct uzi{
	int l,r,len;
	bool operator < (const uzi & t)const{
		if(len==t.len)return l<t.l;
		return len>t.len;
	}
};
set<uzi>s;
int ans[N];
int main() {
  ios::sync_with_stdio(false);
  for(cin>>t;t;t--){
  	cin>>n;s.clear();s.insert({1,n,n});
  	for(int i=1;i<=n;i++){
  		auto x=*s.begin();
  		int l1,r1,l2,r2;
  		//cout<<x.l<<' '<<x.r<< ' '<<x.len<<endl;
  		if(x.len&1){
  			ans[(x.r+x.l)/2]=i;
  			l1=x.l,r1=(x.r+x.l)/2-1;
  			l2=(x.r+x.l)/2+1,r2=x.r;
  		}else{
  			ans[(x.r+x.l-1)/2]=i;
  			l1=x.l,r1=(x.r+x.l-1)/2-1;
  			l2=(x.r+x.l-1)/2+1,r2=x.r;
  		}
  		s.erase(x);
  		if(l1<=r1)s.insert({l1,r1,r1-l1+1});
  		if(l2<=r2)s.insert({l2,r2,r2-l2+1});
  	}
  	for(int i=1;i<=n;i++)cout<<ans[i]<<' ';cout<<'\n';
  }
 	return 0;
}

E.K-periodic Garland
思路:显然要将n个位置按模k的结果分成k组进行分别判断。
每一组dp计算将这一组变成合法的最小操作数即可。
d p i dp_i dpi表示1-i的合法最少操作,那么根据第i个跟第i-1个是否连续可以推出转移方程:
1.连续 d p i = m i n ( d p i − 1 , i ) dp_i=min(dp_{i-1},i) dpi=min(dpi1,i)
2.不连续 d p i = m i n ( d p i − 1 + a i − a i − 1 − 1 , i ) dp_i=min(dp_{i-1}+a_i-a_{i-1}-1,i) dpi=min(dpi1+aiai11,i)
然后在每个i处对答案进行更新即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int t,n,k,f[N];
char a[N];
vector<int>v;
int main() {
  ios::sync_with_stdio(false);
  for(cin>>t;t;t--){
  	cin>>n>>k>>a+1;
  	int ans=1e9,cnt=0;
  	for(int i=1;i<=n;i++){
  		cnt+=(a[i]=='1');
  	}
  	ans=cnt;
  	for(int i=1;i<=k;i++){
  		int now=1;v.clear();
  		for(int j=i;j<=n;j+=k,now++){
  			if(a[j]=='1')v.pb(now);
  		}
  		if(!v.size())continue;
  		for(int j=0;j<=(int)v.size();j++)f[j]=1e9;
  		f[0]=0;
  		for(int j=1;j< (int)v.size();j++){
  			if(v[j]==v[j-1]+1){
  				f[j]=min(f[j-1],j);
  			}else{
  				f[j]=min(f[j-1]+(v[j]-v[j-1]-1),j);
  			}
  			ans=min(ans,cnt-(int)v.size()+f[j]+((int)v.size()-1-j));
  		}
  		ans=min(ans,cnt-(int)v.size()+f[(int)v.size()-1]);
  	}
  	cout<<max(0,ans)<<'\n';
  }
 	return 0;
}

F.Decreasing Heights
思路:显然路径中至少有一个位置的高度是不变的,否则必然不是最优解。
那么枚举高度不变的位置,dp计算从这个点出发,走到左上和右下的最少操作数即可。
ps:当起点的高度确定的时候,起点能到达的每个点的高度都是确定的。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int t,n,m,vis[111][111];
LL a[111][111],dp[111][111];
LL b[111][111];
int main() {
  ios::sync_with_stdio(false);
  for(cin>>t;t;t--){
  	cin>>n>>m;LL ans=LLONG_MAX;
  	for(int i=1;i<=n;i++){
  		for(int j=1;j<=m;j++)cin>>a[i][j];
  	}
  	for(int i=1;i<=n;i++){
  		for(int j=1;j<=m;j++){
  			for(int x=1;x<=n;x++){
  				for(int y=1;y<=m;y++)dp[x][y]=1e18;
  			}
  			b[i][j]=a[i][j];
  			dp[i][j]=0;
  			for(int x=i;x>=1;x--){
  				for(int y=j;y>=1;y--){
  					if(x==i&&y==j)continue;
  					if(x+1<=i ){
  						b[x][y]=b[x+1][y]-1;
  						if(a[x][y]>=b[x][y])
  						dp[x][y]=min(dp[x][y],dp[x+1][y]+abs(a[x][y]-b[x][y]));
  					}
  					if(y+1<=j){
  						b[x][y]=b[x][y+1]-1;
  						if(a[x][y]>=b[x][y])
  						dp[x][y]=min(dp[x][y],dp[x][y+1]+abs(a[x][y]-b[x][y]));
  					}
  				}
  			}
  			for(int x=i;x<=n;x++){
  				for(int y=j;y<=m;y++){
  					if(x==i&&y==j)continue;
  					if(x-1>=i){
  						b[x][y]=b[x-1][y]+1;
  						if(a[x][y]>=b[x][y])
  						dp[x][y]=min(dp[x][y],dp[x-1][y]+abs(a[x][y]-b[x][y]));
  					}
  					if(y-1>=j){
  						b[x][y]=b[x][y-1]+1;
  						if(a[x][y]>=b[x][y])
  						dp[x][y]=min(dp[x][y],dp[x][y-1]+abs(a[x][y]-b[x][y]));
  					}
  				}
  			}
  			//cout<<i<<' '<<j<< ' '<<dp[1][1]<<' '<<dp[n][m]<<endl;
  			ans=min(ans,dp[1][1]+dp[n][m]);
  		}
  	}
  	cout<<ans<<'\n';
  }
 	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值