zoukankan      html  css  js  c++  java
  • [NC13C]形态形成场/[Gym100430B]Divisible Substrings

    [NC13C]形态形成场/[Gym100430B]Divisible Substrings

    题目大意:

    (m(mle26))个字符串替换式(S_i(|S_ile100|)),表示某个大写字母对应的字符串。比如(A ightarrow BB,B ightarrow CC0,C ightarrow 123),代表 (A=12312301231230,B=1231230,C=123)。最后一个对应串只包含数字,其余只包含数字和在它之后的大写字母。字母由'A'开始依次出现,问'A'所代表的字符串有多少子串满足:

    • 这个子串为单个字符'0'或没有前导'0'
    • 把这个子串看作一个十进制数后模(n(nle30))等于(0)

    答案对(r(rle10^9))取模。

    思路:

    对于每一段字符串维护其必要信息,每次暴力合并维护信息。具体见代码注释。

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    typedef long long int64;
    const int K=26,S=101,N=30,D=10;
    int n,mod,m;
    char s[K][S];
    struct Node {
    	int num,cnt,len,pre[N][N],suf[N];
    	//num: 值%n 
    	//cnt: 满足条件的子串数 
    	//len: 10^{长度}%n 
    	//pre[i][j]: 前缀num=i、len=j个数 
    	//suf[i]: 后缀num=i个数 
    };
    Node t[D],f[K];
    inline void merge(Node &a,const Node &b) {
    	(a.cnt+=b.cnt)%=mod;
    	for(register int i=0;i<n;i++) {
    		for(register int j=0;j<n;j++) {
    			const int k=(n-(int64)i*j%n)%n;
    			(a.cnt+=(int64)b.pre[k][j]*a.suf[i]%mod)%=mod;
    		}
    	}
    	for(register int i=0;i<n;i++) {
    		for(register int j=0;j<n;j++) {
    			(a.pre[((int64)a.num*j+i)%n][j*a.len%n]+=b.pre[i][j])%=mod;
    		}
    	}
    	int tmp[n];
    	memcpy(tmp,b.suf,sizeof tmp);
    	for(register int i=0;i<n;i++) {
    		(tmp[((int64)i*b.len+b.num)%n]+=a.suf[i])%=mod;
    	}
    	memcpy(a.suf,tmp,sizeof tmp);
    	a.num=((int64)a.num*b.len+b.num)%n;
    	a.len=(int64)a.len*b.len%n;
    }
    int main() {
    	freopen("divisible.in","r",stdin);
    	freopen("divisible.out","w",stdout);
    	n=getint(),mod=getint(),m=getint();
    	for(register int i=0;i<m;i++) {
    		while(getchar()!='>');
    		scanf("%s",s[i]);
    	}
    	for(register int i=0;i<D;i++) {
    		t[i].num=i%n;
    		t[i].cnt=i%n==0;
    		t[i].len=10%n;
    		t[i].pre[i%n][10%n]=1;
    		t[i].suf[i%n]=i!=0;//0本身不可以作为后缀进行合并
    	}
    	for(register int i=m-1;i>=0;i--) {
    		f[i].len=1;
    		for(register int j=0;s[i][j];j++) {
    			merge(f[i],isdigit(s[i][j])?t[s[i][j]-'0']:f[s[i][j]-'A']);
    		}
    	}
    	printf("%d
    ",f[0].cnt);
    	return 0;
    }
    
  • 相关阅读:
    1093 Count PAT's(25 分)
    1089 Insert or Merge(25 分)
    1088 Rational Arithmetic(20 分)
    1081 Rational Sum(20 分)
    1069 The Black Hole of Numbers(20 分)
    1059 Prime Factors(25 分)
    1050 String Subtraction (20)
    根据生日计算员工年龄
    动态获取当前日期和时间
    对计数结果进行4舍5入
  • 原文地址:https://www.cnblogs.com/skylee03/p/9359290.html
Copyright © 2011-2022 走看看