模拟赛20231003 T1

发布时间 2023-11-17 13:00:54作者: wscqwq

你有一个二进制串长度为N,串内包含0 和1 两个数字。现在用一种特殊的算法对该串进
行加密,加密方式是给定一个整数K 满足1 ≤ K ≤ N。对于该串内每个长度为K 的区间,计
算出该区间内数字的和,放进一个新序列里。新序列一共有N −K + 1 项,第i 项代表原序列
中第i 项到第i + K − 1 项的和。
现在给你加密后的序列,请你求出原序列有多少种不同的可能性?为了避免答案过大,请
你对1000003 取模。
1 ≤ N ≤ 106, 1 ≤ K ≤ N.

考虑根据给定的方程组,先确定可以确定的(注意,后面的关系可能会影响前面的),然后利用组合数计算。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000010,mod=1000003;
int n,k,a[N];
char val[N];
void read(int &x){
	x=0;
	char c=getchar();
	bool fh=0;
	while(!isdigit(c)){
		if(c=='-')fh=1;
		c=getchar();
	}
	while(isdigit(c)){
		x=x*10+c-48;
		c=getchar();
	}
	if(fh)x=-x;
}
ll qpow(ll a,int b){
	ll res=1;
	while(b){
		if(b&1)res=res*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return res;
}
int main(){
	freopen("bit.in","r",stdin);
	freopen("bit.out","w",stdout);
	read(n),read(k);
	memset(val,-1,sizeof val);
	for(int i=1;i<=n-k+1;++i){
		read(a[i]);
//		printf("%d\n",a[i]);
		if(a[i]<0||a[i]>k){
			puts("0");
			return 0;
		}
	}
	for(int i=2;i<=n-k+1;++i){
		if(abs(a[i]-a[i-1])>1){
			puts("0");
			return 0;
		}
		//i-1 and i+k-1
		if(a[i]!=a[i-1]){
			val[i-1]=a[i]<a[i-1];
			int fst=(i-1)%k;
			if(!fst)fst+=k;
			if(!~val[fst])val[fst]=val[i-1];
		}
	}
	int tot=a[1],cnt=k;
	for(int i=1;i<=k;++i)
		if(~val[i])tot-=val[i],--cnt;
	//C(cnt,tot)
//	printf("%d %d\n",tot,cnt);
	if(tot<0||cnt<0||cnt<tot){
		puts("0");
		return 0;
	}
	ll fz=1;
	for(int i=1;i<=cnt;++i)fz=fz*i%mod;
	ll fm=1;
	for(int i=1;i<=tot;++i)fm=fm*i%mod;
	for(int i=1;i<=cnt-tot;++i)fm=fm*i%mod;
	printf("%lld",fz*qpow(fm,mod-2)%mod);
	return 0;
}