Codeforces Round #841 (Div. 2)

题目链接

A. Joey Takes Money

题目描述

在这里插入图片描述

input

在这里插入图片描述

output

在这里插入图片描述

题意:

有一个长度为n的数组,你可以进行一步操作,选择两个i,j,然后再选择两个数x,y,使得a[i]a[j] = xy,然后将a[i] = x,a[j] = y,问任意步操作后的数组的最大和是多少。

思路:

两个数的乘积相等的话要是让他们加和尽可能大的话就是两个数相差尽可能大,那就是答案就是所有数的乘积然后n-1个1,下面看代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
void solve(){
	int n;
	scanf("%lld",&n);
	int ans = 1;
	for(int i=1;i<=n;i++){
		int x;
		scanf("%lld",&x);
		ans *= x;
	}
	printf("%lld\n",(ans+n-1)*2022);
}
signed main(){
	int _;
	for(cin>>_;_;_--) solve();
	return 0;
} 

B. Kill Demodogs

题目描述

在这里插入图片描述

题意:

给你一个数n,有一个大小为nn的矩阵,第i行第j列的单元的权值是ij,现在你可以向右走或者向下走,现在问你能获得的权值的最大值是多少?

思路:

这个跟上一个题刚好是相反的,这个是让i和j尽量相等,走对角线,然后就是右下右下这么走,先右再下,对角线是一个完全平方和,可以用n*(n+1)*(2n+1)/6这个公式来实现,那么对角线上面那一个斜线的和就是每次+1,+2,+3,…,+n-1,画一下就出来了,然后因为要取模,所以说除法得用费马小定理处理一下,下面看代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int mod = 1e9+7;
int ksm(int x,int n){
	int ans = 1;
	while(n){
		if(n & 1) ans = ans * x % mod;
		n >>= 1;
		x = x*x%mod;
	}
	return ans;
}
void solve(){
	int n;
	scanf("%lld",&n);
	printf("%lld\n",(n*(n+1)%mod*(2*n+1)%mod*ksm(3,mod-2)%mod-n*(n+1)%mod*ksm(2,mod-2)%mod+mod)*2022%mod);
}
signed main(){
	int _;
	for(cin>>_;_;_--) solve();
	return 0;
} 

C. Even Subarrays

在这里插入图片描述

题意:

给你一个数组,问有多少个区间满足区间的异或和的因子个数是偶数

思路:

除了完全平方数,其他的数的因子个数都是偶数,所以说只要是求出来有多少个完全平方数就行了,做法就是整一个数组记录前缀异或和,然后对于当前的数,只要求出来有多少个左边界使得这个区间的异或和为完全平方数就行了,因为每一个数都是小于等于n的,所以说直接用数组来维护就行了,用map的话会超时,因为本来复杂度已经是nsqrt(n)了,会被卡常,而且注意要开四倍空间,因为运行中的话会数组越界,这个地方需要点细节,下面看代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int mod = 1e9+7;
const int N = 8e5+10;
int mp[N];
void solve(){
	int n;
	scanf("%lld",&n);
	for(int i=0;i<=n*2;i++) mp[i] = 0;
	int ans = 0,k = 0;
	mp[0] = 1;
	for(int i=1;i<=n;i++){
		int x;
		scanf("%lld",&x);
		for(int j=0;j*j<=n*2;j++){
			ans += mp[(j*j)^k^x];
		}
		k ^= x;
		mp[k]++;	
	}
	printf("%lld\n",n*(n+1)/2-ans);
}
signed main(){
	int _;
	for(cin>>_;_;_--) solve();
	return 0;
} 

D. Valiant’s New Map

在这里插入图片描述

题意:

给你一个nm的矩阵,让你找到一个最大的size,使得存在一个sizsiz的方阵,方阵中的所有数都大于size

思路:

二分size,对于每一个size,首先预处理一遍,将数组中的比size大的数都变成size,然后前缀和就行,下面看代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int mod = 1e9+7,N = 2e6+10;
int n,m;
int g[N],f[N],s[N];
inline int find(int i,int j){
	return i*m + j;
} 
bool check(int siz){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			s[find(i,j)] = min(siz,g[find(i,j)]);
			f[find(i,j)] = f[find(i-1,j)] + f[find(i,j-1)] - f[find(i-1,j-1)] + s[find(i,j)];
		}
	}
	for(int i=siz;i<=n;i++){
		for(int j=siz;j<=m;j++){
			int x1 = i-siz+1,y1 = j-siz+1;
			int t = f[find(i,j)] - f[find(x1-1,j)] - f[find(i,y1-1)] + f[find(x1-1,y1-1)];
			if(t >= siz*siz*siz) return true;
		}
	}
	return false;
}
void solve(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%lld",&g[find(i,j)]);
		}
	}
	int l = 1,r = min(n,m),ans = -1;
	while(l <= r){
		int mid = l + r >> 1;
		if(check(mid)) ans = mid,l = mid + 1;
		else r = mid - 1;
	}
	printf("%lld\n",ans);
}
signed main(){
	int _;
	for(cin>>_;_;_--) solve();
	return 0;
} 

E. Graph Cost

在这里插入图片描述

题意:

给你一个n和m,现在有一个点数为n的图,一开始是没有边的,有一种操作,你可以选一个数k,然后加k+1条边,这些边的两个端点的最大公约数必须是k,不能出现重边,自环,每进行一步操作就会产生k+1的代价,现在问你正好添加m条边的最小代价是多少,如果没有的话就输出-1。

思路:

首先要预处理出来每一个最大公约数有多少点对,这个有两种办法,莫比乌斯反演和dp,我这里用的是dp,首先k的倍数有n/k个,然后只需要k的一倍就行,所以说就可以从大到小dp,然后调和级数算出来时间复杂度是O(nlogn)
,然后从大到小贪心就行,下面看代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N = 1e6+10;
int dp[N];

void solve(){
	int n,m;
	scanf("%lld%lld",&n,&m);
	for(int i=n;i>=2;i--){
		dp[i] = (n/i)*(n/i-1)/2;
		for(int j=2*i;j<=n;j+=i) dp[i] -= dp[j];
	}	
	int ans = 0;
	for(int i=n;i>=2;i--){
		if(m < i-1) continue;
		int k = m / (i-1),l = dp[i] / (i-1);
		m -= min(k,l)*(i-1);
		ans += min(k,l)*i;
		if(m == 0) break;
	}
	if(m) printf("-1\n");
	else printf("%lld\n",ans);
}
signed main(){
	int _;
	for(cin>>_;_;_--) solve();
	return 0;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇智波一打七~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值