zoukankan      html  css  js  c++  java
  • #3164. 「CEOI2019」立方填词

    题目描述

    题解

    先按照长度分类,因为正反读都可以,所以对于每个长度我们可以把串正反都记录下来并且去重,由于我们只关心首尾的字母是什么,所以我们可以记录 $g[a][b]$ 表示开始为 $a$ ,结尾为 $b$ 的串有多少个。

    然后这是一个正方体,最暴力我们可以考虑枚举每个角是什么,然后统计方案,但事实上我们可以先统计形如下图的方案数,即不管棱的交点放了什么,如果剩下的顶点分别 $b,c,d$ 的话有多少种方案,我们把这个方案数设为 $f[b][c][d]$ 。

    然后我们可以发现形如下图,我们可以把正方体分成 $4$ 个上图图形,即顶点 $A,B,C,D$ ,剩下的顶点如果填上 $a,b,c,d$ 的话,那方案数就是 $f[a][b][c] imes f[a][b][d] imes f[a][c][d] imes f[b][c][d]$ 。

    然后我们需要卡常,比如求 $f$ 的时候让 $b le c le d$ 即可,求方案数的时候让 $a le b le c le d$ 即可,注意求方案数要乘上排列数。

    代码

    #include <bits/stdc++.h>
    #define U unsigned long long
    using namespace std;
    const U B=793999;
    const int P=998244353,N=62;
    char ch[15];map<U,int>mp;
    int n,m,g[15][N][N],f[N][N][N],t[N],s;
    int X(int x){return x>=P?x-P:x;}
    int G(char x){
        if (x>='a' && x<='z') return x-'a';
        if (x>='A' && x<='Z') return x-'A'+26;
        return (x^48)+52;
    }
    int main(){
        cin>>n;
        for (int i=1;i<=n;i++){
            scanf("%s",ch+1);
            m=strlen(ch+1);U v=0;
            for (int j=1;j<=m;j++) v=v*B+ch[j];
            if (!mp.count(v))
                mp[v]=1,g[m][G(ch[1])][G(ch[m])]++;
            v=0;
            for (int j=m;j;j--) v=v*B+ch[j];
            if (!mp.count(v))
                mp[v]=1,g[m][G(ch[m])][G(ch[1])]++;
        }
        for (int x=3;x<=10;x++){
            memset(f,0,sizeof f);
            for (int a=0;a<N;a++)
                for (int b=0;b<N;b++) if (g[x][a][b])
                    for (int c=b;c<N;c++) if (g[x][a][c])
                        for (int d=c;d<N;d++) if (g[x][a][d])
                            f[b][c][d]=X(f[b][c][d]+1ll*g[x][a][b]*g[x][a][c]%P*g[x][a][d]%P);
            int p=24;
            for (int a=0;a<N;a++){
                t[a]++;p/=t[a];
                for (int b=a;b<N;b++){
                    t[b]++;p/=t[b];
                    for (int c=b;c<N;c++) if (f[a][b][c]){
                        t[c]++;p/=t[c];
                        for (int d=c;d<N;d++){
                            t[d]++;p/=t[d];
                            s=X(s+1ll*p*f[a][b][c]%P*f[a][b][d]%P*f[a][c][d]%P*f[b][c][d]%P);
                            p*=t[d];t[d]--;
                        }
                        p*=t[c];t[c]--;
                    }
                    p*=t[b];t[b]--;
                }
                p*=t[a];t[a]--;
            }
        }
        cout<<s<<endl;return 0;
    }
  • 相关阅读:
    2018 ACM 网络选拔赛 徐州赛区
    2018 ACM 网络选拔赛 焦作赛区
    2018 ACM 网络选拔赛 沈阳赛区
    poj 2289 网络流 and 二分查找
    poj 2446 二分图最大匹配
    poj 1469 二分图最大匹配
    poj 3249 拓扑排序 and 动态规划
    poj 3687 拓扑排序
    poj 2585 拓扑排序
    poj 1094 拓扑排序
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/12328949.html
Copyright © 2011-2022 走看看