丰风正在安排会议。会议室里有n排m列的座位。正好有n个学生参加会议,包括几个调皮的学生和几个认真的学生。学生被从1到n数点。学生将按顺序进入会场。当第i位同学进入会场时,他将坐在第1排的第1列,已经入座的同学将向后移动一个座位。具体来说,坐在第i行第j (1 SjS m-1)列的学生将移动到第i行第(j+1)列的学生,坐在第i行第m列的学生将移动到第(i +1)行第1列的学生。
题解:
我们要分别计算好的行列,对于行来说我们可以把它看作是一个长度为m的滑动窗口,
对于i >= m
f[i] = f[i-m]
只用判断i前长度为m的一段是否含1即可
相当于现在A位置新进来一个学生,看B上面的一行是否有1
对于判断列,我们可以发现,如果某一列标记过了,那么就不会变,所以我们每次遍历到的列没有标记并且s[i] = 1,并且++
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<set>
using namespace std;
#define int long long
const int N = 4e6 + 10;
typedef pair<int, int> PII;
string s;
int c[N];
int f[N];
int sum[N];
void solve()
{
int n,m;
cin >>n >> m;
cin >> s;
s = " " + s;
for(int i = 1;i <= n*m;i++)
{
sum[i] = sum[i - 1] + (s[i] - '0');
}
for(int i = 1;i <= n*m;i++)
{
if(i >= m)
f[i] = f[i - m];
f[i] += (sum[i] - sum[max(0ll,i-m)] > 0);
}
int now = 1;
int cnt = 0;
for(int i = 1;i <= n*m;i++)
{
if(c[now] == 0&&s[i] == '1')
{
c[now] = 1;
++cnt;
}
cout << cnt + f[i] <<" ";
now ++;
if(now == m + 1)
now = 1;
}
cout << "\n";
for(int i = 1;i <= n*m;i++)
{
c[i] = 0;
sum[i] = 0;
f[i] = 0;
}
}
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
int t = 1;
cin >> t;
//scanf("%lld",&t);
while (t--)
{
solve();
}
}
//3 F
//5 B
//6 F
//9 F
//10 B
//12 F
//15 FB
//18 FB