LA 3641 Leonardo的笔记本 & UVA 11077 排列统计

LA 3641 Leonardo的笔记本

题目

给出26个大写字母的置换B,问是否存在要给置换A,使得 \(A^2 = B\)

分析

将A分解为几个循环,可以观察经过乘积运算得到\(A^2\)后,循环有什么不同。将循环画成一个环,给他们标号\(0,1,\cdots,n-1\), 0号指向1号,n-1号指向1号。如果 n 是奇数,那么可以发现\(A^2\)中,0号指向了2号,2号指向了4号...n-1号指向了1号,1号指向3号...n-2号指向0号,他们依然是一个环。但是如果 n 是偶数,那么0号指向了2号,2号指向了4号,n-2号指向了0号,这一半元素单独构成一个环,另一半元素单独构成一个环。
回到题目中,我们找到B中所有的环,对于B中长度为奇数的环,我们可以选择在A中用同样长度的一个环来得到它,也可以选择用一个长度为2倍的环来得到它。而对于B中长度为偶数的环,我们只能选择在A中用长度为它二倍的环来得到它,所以在B中同一长度为偶数的环,他们的个数必须是偶数个。

char s[30];
int T, vis[N], cnt[30];
int main() {
    scanf("%d", &T);
    while(T--){
        scanf("%s", s);
        memset(cnt, 0, sizeof cnt);
        memset(vis, 0, sizeof vis);
        for (int i = 0; i < 26;i++){
            if(!vis[i]){
                int j = i, n = 0;
                do{
                    vis[j] = 1;
                    j = s[j] - 'A';
                    n++;
                } while (j != i);
                cnt[n]++;
            }
        }
        int flag = true;
        for (int i = 2; i <= 26;i+= 2){
            if(cnt[i] % 2 == 1)
                flag = false;
        }
        puts(flag ? "Yes" : "No");
    }
    return 0;
}

UVA 11077 排列统计

题意:

给定一个长度为n的排列,可以通过一系列的交换变成{1,2,3,...n}。给定n和k,统计有多少个排列至少需要交换 k 次才能变成{1,2,...,n}。

分析

把这个长度为n的排列看成一个置换,我们每次交换操作肯定是在循环中选择两个数字进行交换。每次交换可以等效于将环的长度减1,也就是把某个元素从环中剔除。(可以举几个例子),所以c个元素的循环,总共需要c-1次交换操作。
f[i][j]为长度为i的循环需要交换 j 次才能变成顺序排列的排列个数。
\(f[i][j] = f[i-1][j-1] * (i-1) + f[i-1][j]\)
前面的表示将第 i 个元素随便插入到前面 i-1 个元素组成的若干个圆排列中(联系第一类斯特林数),后面的表示将第 i 个元素单独构成一个环,它并不对交换操作造成贡献

ull f[N][N];

int main() {
    memset(f, 0, sizeof f);
    f[1][0] = 1;
    for (int i = 2; i <= 21;i++){
        for (int j = 0; j < i;j++){
            f[i][j] = f[i - 1][j];
            if(j > 0)
                f[i][j] += f[i - 1][j - 1] * (i - 1);
        }
    }
    int n, k;
    while(scanf("%d%d",&n,&k) == 2 && n)
        printf("%llu\n", f[n][k]);
    return 0;
}
posted @ 2020-02-19 21:26  kpole  阅读(111)  评论(0编辑  收藏  举报