Gym 101398. K

来源:互联网 发布:php 函数参数类型 编辑:程序博客网 时间:2024/05/17 06:45

题意:给你两串字符,然后告诉你长度k为一段,串一串二在每一段中通过某种映射方式一一对应,得到若干种对应方案,然后问你整个串中有多少种方案使得,所有段均满足。

思路:
  先按题意连边,同一段中,相同的两个字母连边。又易得,两点之间只有边数==段数,才应该在新图中连边。
  得到新图以后,直接搜联通块,联通块为偶数即可。(易证,今年多校也有一个这种题)然后每个联通块的贡献度即为其大小siz/2的阶乘。

#include <bits/stdc++.h>using namespace std;char s1[105], s2[105];int pre[205][205], in[205], vis[205];vector<int>G[205];int siz = 0;int dfs(int u){    vis[u] = 1;    int ret = 1;    for(auto o : G[u])  if(vis[o] == 0) ret += dfs(o);    return ret;}long long fac(int siz){long long ret = 1;for(int i = 1; i <= siz; i++) ret *= i; return ret;};int main(){    int block;    while(~scanf("%d", &block))    {        memset(vis, 0, sizeof(vis));        memset(pre, 0, sizeof(pre));        for(int i = 0; i <= 200; i++)   G[i].clear();        scanf("%s%s", s1 + 1, s2 + 1);        int len = strlen(s1 + 1);        int need = len / block;        for(int i = 1; i <= len; i += block)        {            for(int j = 0; j < block; j++)            {                for(int k = 0; k < block; k++)                {                    if(s1[j + i] == s2[k + i])                    {                        pre[j + 1][k + 1 + block]++, pre[k + 1 + block][j + 1]++;                    }                }            }        }        for(int i = 1; i <= block * 2; i++)        {            for(int j = block + 1; j <= block * 2; j++)            {                if(pre[i][j] >= need)                {                    G[i].push_back(j);                    G[j].push_back(i);                    in[i]++, in[j]++;                }            }        }        long long ans = 1;        for(int i = 1; i <= block; i++)        {            if(vis[i])  continue;            int siz = dfs(i);            if(siz & 1) ans = 0;            else ans *= fac(siz/2);        }        printf("%I64d\n", ans);    }    return 0;}
原创粉丝点击