zoukankan      html  css  js  c++  java
  • [AGC027E]ABBreviate

    Description

    AGC027E
    给定一个仅由(AB)构成的字符串(S),给定两个操作,把(AA)换成(B),和把(BB)换成(A),问由这个字符串和任意次操作可以得到几种字符串。

    Solution

    AGC好难啊(摔

    首先,如果不能操作,答案是(0)

    我们令(A=1,B=2),这样就会有一个美妙的性质:所有字符的和在操作的时候在模(3)意义下不变,我们记这个和为(p(S))。然后我们可以得到一个结论:一个字符串(S)可以变成字符(c),当且仅当:(S=c)(p(S)=p(c))(S)可以操作。这个条件的必要性很好证明,而充分性证明也比较简单:当(S)中的连续字符长度为(2)时,可以合并这两个字符,并且字符串长度减小;而当(S)中的连续字符长度大于(2)时,可以合并与不同字符相邻的那一端的字符(如果只有一种字符的话,自己证吧),字符串长度也减少;这样,字符串长度不断减少,一定可以达到(1),这时的(S'=c)

    这样问题就转化为:求出这样的(T)的数量:将(S)划分为(|T|)段,第(i)段的(p)值与(T)中的第(i)个字符的(p)值相等。我们可以贪心的构造这样的(T):让每一段的长度尽可能的小,如果分出(|T|)段后,剩余部分的(p)值为(0),那就是一个合法的(T)

    这样,就只需要一个简单的DP就行了我们递推的来做,(f_i)表示前(i)个字符看作一段的方案数,如果(p(S_{i+1,n})=0),那么(i)之后的位置可以看成是剩余的位置(f_i)的初值为(1),否则为(0)。然后,我们可以在(i)之后加一段(A)或是(B),这样就要记录各个(p)值最后一次出现的位置,累加即可。具体实现看代码。

    Code

    #include <cstdio>
    
    const int N = 1e5 + 10;
    const int MOD = 1e9 + 7;
    
    char s[N];
    int a[N], n, f[N], nxt[3];
    
    int main() {
    	scanf("%s", s);
    	for (; s[n]; ++n) a[n+1] = (a[n] + s[n] - 'a' + 1) % 3; // 求前缀和 
    	// 判断是否可以操作 
    	int flag = 0;  
    	for (int i = 1; i < n; ++i) {
    		if (s[i] == s[i-1]) flag = 1;
    	}
    	if (!flag) {
    		puts("1");
    		return 0;
    	}
    	// 递推 
    	f[n] = 1;
    	for (int i = 0; i < 3; ++i) nxt[i] = i == a[n] ? n : n + 1;
    	for (int i = n-1; i; --i) {
    		f[i] = a[i] == a[n]; // 后面可不可以不分段 
    		for (int c = 1; c <= 2; ++c) {
    			(f[i] += f[nxt[(a[i]+c)%3]]) %= MOD; // 后面加一段A或B 
    		}
    		nxt[a[i]] = i; // 记录该p值最后一次出现的位置 
     	}
     	printf("%d
    ", (f[nxt[1]] + f[nxt[2]]) % MOD);
    	return 0;
    }
    
  • 相关阅读:
    jpa项目倒入eclipse中,无法识别注解的实体类
    上传文件的js控件,无刷新
    Maven 安装
    location 浅解析
    小程序 上传图片(多张、多次上传),预览图片 删除图片
    小程序 跳转问题 (来源见注明)
    GIT 安装和升级
    span 不使用float 靠右对齐且垂直居中
    PHP 根据php传的值修改 select 中动态生成的 option 组的默认选中值
    MAC 隐藏功能
  • 原文地址:https://www.cnblogs.com/wyxwyx/p/agc027e.html
Copyright © 2011-2022 走看看