【SCPC第三次对抗赛】

本文解析了SCPC对抗赛中的两个题目,涉及区间和的计数问题和矩阵奇偶性判断。第一个是通过前缀和计算符合条件的区间个数,第二个是讨论了矩阵1的奇偶性在不同大小情况下如何判断。涉及的编程技巧包括状态压缩和动态规划。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


SCPC第三次对抗赛

---hp枫落出题部分

J:雨散枫飘佳靥去

链接: link

先从题目中提取关键信息: r − l + 1 r-l+1 rl+1= ∑ i = l r a i \sum_{i=l}^{r} a{_i} i=lrai
求符合此条件的区间 [ l , r ] [l,r] [l,r]的个数

我们用sum数组代表数组a的前缀和数组。
那么我们将式子进行转化
r − l + 1 r-l+1 rl+1= s u m r − s u m l − 1 sum_r-sum_{l-1} sumrsuml1
-> s u m r − r = s u m l − 1 − l − 1 sum_r-r=sum_{l-1}-l-1 sumrr=suml1l1
c i = s u m i − i c_i=sum_i-i ci=sumii
那么接下来我们就只需要考虑: 对于一个 r r r来说,有多少符合条件的 l l l了。
也就是对于 [ 1 , r − 1 ] [1,r-1] [1,r1]里, c r c_r cr出现的次数,这个我们可以用桶来记录个数。

坑点: 注意由于数组中包含0,所以要考虑 s u m i − i sum_i-i sumii可能是负数
所以我们可以把每个数加一个够大的基数,或者直接用map来当桶。

下面展示一些 主要代码

void solve(){
	int n; cin >> n;
	for(int i=1; i<=n; i++) cin >> a[i];
	map<int, int>mp;
	int sum = 0, res = 0;
	mp[0] = 1;
	for(int i=1; i<=n; i++){
		sum += a[i];
		res += mp[sum - i];
		mp[sum-i]++;
	}
	cout << res << endl;
}

I:凢凢传之勾引小学妹

带水题 自己画几个循环就会发现了~~~~
(今年看凢凢的了!XD:)

H:严佬的后宫(hard version)

原题链接: link

注意:easy版本是hard的阉割版 就不单独讲了

tips: 题面说了n<=m
首先很显然 如果矩阵的n>=4 那么这个矩阵一定能被拆为诺干个22的小矩阵
由于每个2
2的小矩阵1的个数都是奇数 那么4个小矩阵和在一起1的个数一定是偶数
请添加图片描述

        if(n>=4){
			cout<<-1<<endl;
			return 0;
	}

所以我们只需考虑n=1,n=2,n=3的情况
一、首先n=1

        if(n==1){
			cout<<0<<endl;
			return 0;

这个肯定不需要解释吧!

二、再考虑n=2 也就是easy version

我们先考虑第一列 其实只有两种情况
1:第一列有奇数个1
2:第一列有偶数个1
为什么呢? 因为当知道第一列的奇偶性后 第二列的是一定的 以此类推 第三列也是一样的 所以只要我们暴力计算下2种情况就行了!

    void slove2(){
		int ans1 = 0,ans2 = 0;
    	for(ll i=1;i<=m;i+=2){
			if(st[i]==0||st[i]==3)ans1++;
			if((st[i+1]==1||st[i+1]==2)&&i+1<=m)ans1++;
		}
		for(ll i=1;i<=m;i+=2){
			if(st[i]==1||st[i]==2)ans2++;
			if((st[i+1]==0||st[i+1]==3)&&i+1<=m)ans2++;
		}
    	cout<<min(ans1,ans2)<<'\n';
}

tips:st储存的是01的状态

    FOR(j,1,m){
		ll x=0;
		FOR(i,1,n){
			if(i)x<<=1;
			if(a[i][j]==1)x++;
		}
		st[j]=x;
	}
}

三、n=3的情况
很显然3*3的矩阵是可以满足题目条件的,我们仍旧考虑列 首先3行的01组合有8种方式 (000 001 010 011 100 101 110 111, 注意这里的是竖着的1列可能的情况
假设当前是第 i 列 显然第 i 列的每种可能一定是从第 i-1 列转移过来的,所以这里我们考虑dp
f[i][j]=f[i-1][p]+(cnt)(0<=j<=8)
cnt为让让这两列满足条件时候前i-1列需要的最少改变次数
:此时前i-1列是满足条件的

这里画个图再强调一下什么叫两列满足条件:
例如010 就只能从111和000转移过来,因为只有这样才满足每个2*2的矩阵1的个数为奇数。
在这里插入图片描述
我这里是用讲01串进行状态压缩来dp的 也就是状压dp

tips:bp是处理出这两个状态之间需要操作的变化函数

vector<ll>g[8];
ll f[N][10];
void slove3(){
	g[0]={2,5};g[1]={4,3};g[2]={0,7};g[3]={1,6};
	g[4]={1,6};g[5]={0,7};g[6]={3,4};g[7]={2,5};
	for(ll i=0;i<8;i++)f[1][i]=bp(i^st[1]);
	for(ll i=2;i<=m;i++){
		for(ll j=0;j<8;j++){
			f[i][j]=min(f[i-1][g[j][0]]+bp(j^st[i]),
						f[i-1][g[j][1]]+bp(j^st[i]));
		}
	}
	ll ans=1e9;
	for(ll i=0;i<8;i++)ans=min(ans,f[m][i]);
	cout<<ans<<endl;
	}
}

应该没啥了吧 ~~~~~~~~
大家如果体验感不好真的很抱歉5555555

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值