cf1644-C/D(思维)

6 篇文章 0 订阅

C-Increase Subarray Sums

题意

给定一个数组,可以对其中的 k k k不同元素都加上 x x x,( k k k x x x 题目已给出),求 k k k 的取值为 0 0 0 n n n 时,该数组内连续子段之和的最大值是多少。

考虑用前缀和的思想,求出长度从 1 1 1 n n n 时能够拥有的最大连续子段之和,再枚举 k k k 的取值,则该连续子段能够加上的 x x x 的个数为 m i n ( k , j ) min(k,j) min(k,j),其中 j j j 表示当前枚举的子段的长度。

#include <bits/stdc++.h>
#define int long long
#define PII pair<int,int>

using namespace std;
const int N=5050;
const int mod=998244353;
int a[N],s[N],maxx[N];//maxx中存的为长度为i的最大子段和 
PII p[N];

void solve(){
	int n,x;
	cin>>n>>x;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		s[i]=s[i-1]+a[i];
	}
	int temp;
	for(int i=1;i<=n;i++){
		temp=-1e9;
		for(int j=i;j<=n;j++){
			temp=max(temp,s[j]-s[j-i]); 
		}
		maxx[i]=temp;
	}
	
//	for(int i=1;i<=n;i++){
//		cout<<maxx[i]<<" ";
//	}
//	cout<<endl;
	
	int res=0;
	for(int i=0;i<=n;i++){
		res=0;
		for(int j=0;j<=n;j++)
			res=max(res,maxx[j]+min(i,j)*x);
		cout<<res<<" ";
	}
	cout<<endl;
	return ;
}

signed main(){
	int t;
	cin>>t;
	while(t--)
		solve();
	return 0;
}

D-Cross Coloring

题意

现有一个全为白色的 n ∗ m n * m nm 的矩阵,将有 q q q 个操作,每个操作都将选中点 ( x , y ) (x,y) (x,y) 并对其同行及同列的所有方块同时染成 k k k 个颜色中的任意一种(如某方块之前有颜色也将覆盖)。问有多少种不同的涂色方案。

感觉比 C 更简单(bushi),由于每次操作都会覆盖之前的涂色,因此考虑通过逆序处理,记录从后往前遍历到的未被完全覆盖的点数,并对其对应的行列进行标记。

完全覆盖:当该点所在的行和列在之后的操作都将被覆盖。未完全覆盖:该行或该列还没有被涂色。

由于共有 k k k 种颜色,因此每次遇到未完全覆盖的点时,对答案的贡献均为 ∗ k *k k。为优化操作,当所有行或列都已被覆盖时,之前的操作都不再有意义,直接 b r e a k break break 即可。

#include <bits/stdc++.h>
#define int long long
#define PII pair<int,int>

using namespace std;
const int N=2e5+10;
const int mod=998244353;
int hang[N],lie[N];//改行列的状态 如果标1说明之后寄了 
PII p[N];

int qsm(int a,int k){ 
    int res=1;
    while(k){
        if(k&1) res=res*a%mod;
        a=a*a%mod;
        k/=2;
    }
    return res;
} 

void solve(){
	int n,m,k,q;
	cin>>n>>m>>k>>q;
	int x,y;
	memset(hang,0,sizeof(hang));
	memset(lie,0,sizeof(lie));
	int a=0,b=0;
	for(int i=1;i<=q;i++){
		cin>>p[i].first>>p[i].second;
	}
	int ans=0;
	for(int i=q;i>=1;i--){
		if(!hang[p[i].first]||!lie[p[i].second]){
			ans++;
		}
		if(!hang[p[i].first]){
			hang[p[i].first]=1;
			a++;
		}
		if(!lie[p[i].second]){
			lie[p[i].second]=1;
			b++;
		}
		if(a==n||b==m)
			break;
	}
	cout<<qsm(k,ans)<<endl;
}

signed main(){
	int t;
	cin>>t;
	while(t--)
		solve();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值