2017多校联合第一场 1006题 hdu 6038 Function 循环节

34 篇文章 0 订阅
2 篇文章 0 订阅

题目链接


题意:

Please calculate the quantity of different functions  f  satisfying that  f(i)=bf(ai)  for each  i  from  0  to  n1 .

(嗯...就是这样)


思路:

首先可以将 a 数组划分成若干个循环节,每个节是相互独立的,取其中一个节来看,令其长度为 l

显然,由定义,该节就决定了 bx = y, by = z, ... bxx = x, 的这个循环节有多长,

再看 b,显然我们应该将 b 的循环节 (设长度为 l0) 对应赋给上述循环节,至于长度呢,

1. l0 == l,显然可行,总共有 l 种排列

2. l0 == 1, 显然可行,注意到,此时第一个所赋的值决定了这 l 个式子的值,

即,若赋了 bx = x, 则接下来 l - 1 个式子必然也都是 bx = x, 因为第一个式子决定了 y = x, 继续下去, z = y, 以此类推,

故对每种赋值方法,有且只有 1 种排列,

3. 根据第二点就很容易想到了,l 的所有约数长度的循环节都是可以的,并且第一整段 l0 长度的式子决定了后面若干个整段 l0 长度的式子(和第一整段均一模一样),

故,一旦选定了b的某个循环节,且一旦确定了第一整段的排列,那么长度为 l 的整段的排列都唯一确定了,

而第一整段的排列有 l0 种,


答案就是 \prod_{i = 1}^{k} \sum_{j | l_i} {j \cdot cal_j}i=1kjlijcalj ,其中 kk 是置换 aa 中循环节的个数, l_ili 表示置换 aa 中第 ii 个循环节的长度, cal_jcalj 表示置换 bb 中长度为 jj 的循环节的个数。

官方题解


AC代码如下:

#include <cstdio>
#include <cmath>
#include <cstring>
#define mod 1000000007
#define maxn 100010
typedef long long LL;
int kas, a[maxn], b[maxn], n, m;
LL tot[maxn];
bool in[maxn];
void findcycle(int* a, int n) {
    for (int i = 0; i < n; ++i) {
        if (!in[i]) {
            in[i] = true;
            int ii = a[i], cnt = 1;
            while (ii != i) {
                in[ii] = true;
                ii = a[ii];
                ++cnt;
            }
            ++tot[cnt];
        }
    }
}
void work() {
    for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
    for (int i = 0; i < m; ++i) scanf("%d", &b[i]);
    memset(tot, 0, sizeof(tot));
    memset(in, 0, sizeof(in));
    findcycle(b, m);
    memset(in, 0, sizeof(in));
    LL ans = 1;
    for (int i = 0; i < n; ++i) {
        if (!in[i]) {
            in[i] = true;
            int ii = a[i], cnt = 1;
            while (ii != i) {
//                printf("%d ", ii);
                in[ii] = true;
                ii = a[ii];
                ++cnt;
            }
//            printf("\n");
//            printf("%d %d\n", i, cnt);
            LL mul = 0;
            for (int j = 1; j <= cnt; ++j) {
                if (cnt % j == 0) {
                    mul += (tot[j] * j) % mod;
                    mul %= mod;
                }
            }
            ans *= mul;
            ans %= mod;
        }
    }

    printf("Case #%d: %lld\n", ++kas, ans % mod);
}
int main() {
    while (scanf("%d%d\n", &n, &m) != EOF) work();
    return 0;
}



怎么说呢, 虽然有点马后炮...

然而,这道题应该还是挺好做的

主要是当时太浮躁,

一来认为自己做不出来

二来被前面 02 WA了太多次很丧气

三来感觉当时做得人并不太多(也不知哪来的错觉...

四来就是其它一些琐碎的原因了...

其实主要吧...还就是不想做(叹气


结束之后定下来想了一想,很快就想得八九不离十了...

嗯...挺遗憾的......


接下来都要振作起来啊

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值