D. Tokitsukaze and Meeting

题目:D. Tokitsukaze and Meeting

题意:将一串长度为 n ∗ m n*m nm 01 01 01 字符串,挨个地将字符放到一个 n ∗ m n * m nm 的矩阵中,并求出当第 i i i 个字符放入矩阵后,矩阵有多少个行与列存在字符 1 1 1 ,并依次输出答案。

每次取出字符串的队头元素,放入坐标为 ( 1 , 1 ) (1,1) (1,1) 的位置,而矩阵原来的元素往后移动一格,例如: ( 1 ≤ j ≤ m − 1 ) (1 \leq j \leq m - 1) (1jm1) 放入一个新的元素后, j j j 变成 j + 1 j+1 j+1 ,如果 ( i < n , j = m ) (i < n,j = m) (i<n,j=m) 放入一个新的元素后, i i i 变成 i + 1 i+1 i+1 j j j 变成 1 1 1

思路:求放入第 i i i 元素后,矩阵中有多少个行与列存在字符 1 1 1 。可以将行与列分开计算,最后输出 c o l [ i ] + r o w [ i ] col[i] + row[i] col[i]+row[i] c o l [ i ] 、 r o w [ i ] col[i]、row[i] col[i]row[i] 分别表示当放入第 i i i 个值后,有 c o l [ i ] col[i] col[i] 列存在字符 1 1 1 ,有 r o w [ i ] row[i] row[i] 行存在字符 1 1 1

  • 列计算:将新的元素加入矩阵中后,会发现原来的元素在 1 ∽ m 1\backsim m 1m 列中循环移动,当某一时刻 m m m 列都存在 1 1 1 时,此后加入的元素将不再影响列的数量,将 n ∗ m n * m nm 个元素分成长度为 m m m n n n 个组,对于每组的为 1 1 1 的元素,若所处的列没有 1 1 1 ,则 c o l [ i ] + 1 col[i] + 1 col[i]+1 ,并标记当前列已存在 1 1 1(列的计算与 1 1 1 的所在位置无关,只与当前列是否被标记有关)

  • 行计算:行计算与列计算的方式是完全不同的,主要原因是行为逐行推进,而列是一个循环,且与 1 1 1 所在的位置是相关的。在模拟样例的时候,我们能发现 a 1 a_1 a1 在任意一行的情况都不会超过 m m m 种,情况如下所示:

    a 1 a_1 a1

    a 2 a 1 a_2a_1 a2a1

    a 3 a 2 a 1 a_3a_2a_1 a3a2a1

    . . . ... ...

    a m a m − 1 . . . a 2 a 1 a_ma_{m-1}...a_2a_1 amam1...a2a1

    这便是 a 1 a_1 a1 在一行中的所有情况,对于每种情况,对剩余的元素以 m m m 个元素为一组,进行分组。若分组中存在 1 1 1 ,则表示当前行为 1 1 1 ,再利用前缀和计算出,到当前行时,有多少行存在元素 1 1 1 。在计算的时候可以用双指针 O ( n ∗ m ) O(n * m) O(nm)

在这里插入图片描述

#include<stdio.h>

const int N = 1e6 + 10;
char s[N];
int res[N],row[N],col[N];

int main() {
	int t;
	scanf("%d",&t);
	while(t --) {
		int n,m;
		scanf("%d %d %s",&n,&m,s+1);
		
		for(int i=0;i<=n*m;i++) {
			res[i] = 0;
			row[i] = 0;
			col[i] = 0;
		}
		
		int L = 1,cnt = 0;
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=m;j++) {
				if(s[L] == '1' && col[j] == 0) {
					col[j] = 1;
					cnt ++;
				}
				res[L ++] = cnt;
			}
		}
		
		L = 1,cnt = 0;
		int l = 1,r = 0;
		
		while(L <= n * m) {
			r ++;
			if(s[r] == '1') cnt ++;
			
			if(r - l + 1 > m) {
				if(s[l] == '1') cnt --;
				l ++;
			}
			
			row[L % m] += cnt > 0 ? 1 : 0;
			
			res[L] += row[L % m];
			L ++;
		}
		
		for(int i=1;i<L;i++) printf("%d ",res[i]);
		printf("\n");
	}
	return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值