• UVA12387 Alphabet Soup [Polya + KMP]


    Alphabet SoupAlphabet Soup


    Descriptionmathcal{Description}
    在一个圆中, 一共 360,000360,000 个角度, 初始有PP个物品, 分别在PP个不同的角度, SS 个颜色去染这 PP 个物品, 求方案数量.
    旋转同构 .


    正解部分
    这道题目为项链问题的一个拓展,
    相比项链问题, 该题的 项链 旋转后不一定与原来重合,
    对该问题目标是:  k ,找出所有旋转 k 度后会重合的方案, 以统计答案
    旋转后使得每个角度重合, 等价于每个角度的 间距 相同, 于是将位置数组转换为间距数组,
    进行 环状处理.


    实现部分

    • 将所有物品的角度排序, 进行差分操作
    • 数组拷贝一次放在后方
    • 原始差分数组作为模式串, 倍长数组作为文本串, 进行 KMPKMP 字符串匹配
    • 若匹配成功, 说明旋转若干角度可以与原来重合, 计入 置换总数 G|G| , Ans+=SGcd(P,k)Ans+=S^{Gcd(P,k)}
      其中kk为旋转多少度 .
    • G|G|, 输出答案.

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 360005;
    const int mod = 100000007;
    
    int S;
    int P;
    int Ans;
    int A[maxn<<1];
    int B[maxn];
    int nxt[maxn];
    
    int Gcd(int a, int b){ return !b?a:Gcd(b, a%b); }
    
    int KSM(int a, int b){
            int s = 1;
            while(b){
                    if(b & 1) s = 1ll*s*a % mod;
                    a = 1ll*a*a % mod;
                    b >>= 1;
            }
            return s;
    }
    
    void Get_next(){
            nxt[0] = -1;
            int i = 0, t = -1;
            while(i < P-1){
                    if(t == -1 || B[i] == B[t]) nxt[++ i] = ++ t;
                    else t = nxt[t];
            }
    }
    
    void KMP(){
            int cnt = 0;
            int t_1 = 0, t_2 = 2;
            while(t_2 < (P<<1)){
                    if(t_1 == -1 || B[t_1] == A[t_2]) t_1 ++, t_2 ++;
                    else t_1 = nxt[t_1];
                    if(t_1 == P-1){
                            int k = t_2 - P - 1;
                            Ans = ( 1ll*Ans + KSM(S, Gcd(P, k) ) ) % mod;
                            t_1 = nxt[t_1];
                            cnt ++;
                    }
            }
            Ans = 1ll*Ans*KSM(cnt, mod-2) % mod;
    }
    
    void Work(){
            for(reg int i = 1; i <= P; i ++) A[i] = read();
            if(P == 1){ printf("%d
    ", S); return ; }
            std::sort(A+1, A+P+1);
            for(reg int i = 1; i <= P; i ++) A[i+P] = A[i] + 360000;
            for(reg int i = P<<1; i > 1; i --) A[i] -= A[i-1];
            for(reg int i = 1; i <= P; i ++) B[i-1] = A[i+1];
            Ans = 0;
            Get_next();
            KMP();
            printf("%d
    ", Ans);
    }
    
    int main(){
            S = read(), P = read();
            while(~S && ~P) Work(), S = read(), P = read();
            return 0;
    }
    
    
  • 相关阅读:
    IDEA 2020.1 使用eclipse快捷键
    IDEA 2020.1 配置自定义Maven
    Maven 下载、安装、设置国内镜像
    IDEA 2020.1 下载、安装、激活
    MySQL 5.5/5.7 zip版 下载、安装、卸载、报错
    JDK8 下载、安装、配置环境变量
    如何在虚拟机VM15中安装W10
    虚拟机的安装,VMware-workstation-full-15.5.1-15018445
    为什么要买云服务器
    输入子系统实现的按键驱动
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822576.html
Copyright © 2020-2023  润新知