hdu7101滑动窗口

#include<bits/stdc++.h>
using namespace std;
#define pos(x,y) st[x%y][x/y%len[x%y]]-'a'
//x%y是求 是第几个串,x/y求 是补齐后的串里 第几个字符,%len[x%y]是求原串里是第几个字符
//pos(x,y)求第x个加入的字符,转为int二进制在哪位。(主要是为了区分26个字母) 
typedef long long ll;
const int maxn=105,maxm=15;
int n,len[maxn],cnt[27];
char st[maxn][maxm];
int main(){
	int t,g,ml,f,f2;
	//min公倍数,字符串的最大长度 ,需要出现的所有字符, 
	cin>>t;
	while(t--){
		g=1,ml=0,f=f2=0;
		memset(cnt,0,sizeof(cnt));
		scanf("%d",&n);
		//小细节:按0~n-1存,%n才是正常的。所以下面p2要从-1开始 
		for(int i=0;i<n;i++){
			scanf("%s",st[i]);
			len[i]=strlen(st[i]);
			for(int j=0;j<len[i];j++)
				f|=1<<st[i][j]-'a';
				//先1左移()位 ,在赋值或给f。即将st[i][j]-'a'位变为1 
				//f记录每组数据 的所有字符串 共出现哪些字母 
			if(len[i]>ml) ml=len[i];
			g=g*len[i]/__gcd(g,len[i]);
		}
		int p1=0,p2=-1,tot=(g+ml)*n;
		int ans=tot;
		while(p2<tot){
			//小while里p2在++,所以也要判断下p2<tot 
			//里面2个while并列表示双指针p1p2的移动方式 
			while(f2!=f&&p2<tot){
				++p2;
				++cnt[pos(p2,n)];//存26个字母各出现多少次 
				f2|=1<<pos(p2,n); 
			}
			//用while不用if,因为里面f2在变。有可能++p1为起点的 也满足 
			while(f2==f){
				//ans求各个起点的 最短的 
				ans=min(ans,p2-p1+1);
				//对于以p1为起点的,找到满足的就是最短的,所有p1的不用再考虑了,可以看++p1, 
				--cnt[pos(p1,n)];//所有p1这个位置的字母也去掉 
				if(cnt[pos(p1,n)]==0)
					f2&=~(1<<pos(p1,n));
					//若这个字母次数为0。按位与上0,即除去这位(即起始位这个字母) 
				++p1; 
			}
		}
		printf("%d\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_50904510/article/details/120064500