hdu 6021 MG loves string 子集 容斥 循环节
2017-05-26 10:27
381 查看
题目链接
题意:
一个字符串,每一个字符通过若干次变换可以变回自身(即每个字符都在一个环中)。
问变化次数的期望 * (26 ^ n), n为字符串的长度。
以
2abcdefghijklmnpqrstuvwxyzo
为例,
有两种环,第一种A环长度为12,个数为1;第二种B环长度为1,个数为14
若两位均来自A环,则字符的选择有 12 * 12 种,需变换 lcm(12, 12) = 12 次,共 12 * 12 * 12
若两位均来自B环,则字符的选择有 14 * 14 种,需变换 lcm(1, 1) = 1 次,共 14 * 14 * 1
若分别来自A环与B环,则字符的选择有 14 * 12 种,需变换 lcm(12, 1) = 12 次,共 14*12 * 12 * 2 (第一位第二位交换位置)
期望 * (26 ^ n) 即为上面的三部分求和
然后我就不会做了(。
然后就去百度了
先选择环的集合,再在选定的环的集合(基数为K)中选择元素(容斥原理,取K个集合相交的部分)(其中用快速幂处理)
一道很好的题目(。
参考:
http://www.7zhang.com/index/cms/read/id/296366.html(写得很清楚一看就明白惹,一开始看了各种文章看不明白理解力捉急的我Orz)
http://blog.csdn.net/luricheng/article/details/69367452(这篇也写得很棒)
AC代码如下:
题意:
一个字符串,每一个字符通过若干次变换可以变回自身(即每个字符都在一个环中)。
问变化次数的期望 * (26 ^ n), n为字符串的长度。
以
2abcdefghijklmnpqrstuvwxyzo
为例,
有两种环,第一种A环长度为12,个数为1;第二种B环长度为1,个数为14
若两位均来自A环,则字符的选择有 12 * 12 种,需变换 lcm(12, 12) = 12 次,共 12 * 12 * 12
若两位均来自B环,则字符的选择有 14 * 14 种,需变换 lcm(1, 1) = 1 次,共 14 * 14 * 1
若分别来自A环与B环,则字符的选择有 14 * 12 种,需变换 lcm(12, 1) = 12 次,共 14*12 * 12 * 2 (第一位第二位交换位置)
期望 * (26 ^ n) 即为上面的三部分求和
然后我就不会做了(。
然后就去百度了
先选择环的集合,再在选定的环的集合(基数为K)中选择元素(容斥原理,取K个集合相交的部分)(其中用快速幂处理)
一道很好的题目(。
参考:
http://www.7zhang.com/index/cms/read/id/296366.html(写得很清楚一看就明白惹,一开始看了各种文章看不明白理解力捉急的我Orz)
http://blog.csdn.net/luricheng/article/details/69367452(这篇也写得很棒)
AC代码如下:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <map> #define MAXN 40010 #define MAX 10100 using namespace std; typedef long long LL; int n, m, k, vis[30], loop[30]; const int MOD = 1e9 + 7; vector<pair<int, int> > v; vector<int> v2; LL qpow(LL a, LL b) { LL ret = 1; while (b) { if (b & 1) ret = (ret * a) % MOD; a = (a * a) % MOD; b >>= 1; } return ret % MOD; } int GCD(int a, int b) { if (b == 0) return a; return GCD(b, a % b); } int LCA(int a, int b) { return a / GCD(a, b) * b; } int lca() { int ret = 1; for (int i = 0; i < v2.size(); ++i) ret = LCA(ret, v[v2[i]].first);// printf("v : %d ", v[v2[i]].first); // printf("\n"); return ret; } void work() { scanf("%d", &n); char s[30]; memset(vis, 0, sizeof(vis)); memset(loop, 0, sizeof(loop)); gets(s); // printf("%s\n", s); int a[30]; for (int i = 0; s[i] != '\0'; ++i) a[i] = s[i] - 'a'; for (int i = 0; i < 26; ++i) { if (vis[a[i]]) continue; int x = i, cnt = 1; vis[x] = true; while (a[x] != i) { x = a[x]; vis[x] = true; ++cnt; } // printf("%d ", cnt); ++loop[cnt]; } v.clear(); for (int i = 1; i < 27; ++i) { if (loop[i]) v.push_back(make_pair(i, i * loop[i])); } int setsnum = v.size(); LL ans = 0; for (int i = 1; i < (1 << setsnum); ++i) { LL ans1 = 0; v2.clear(); int cnt = 0; for (int j = 0; j < setsnum; ++j) { if (i & (1 << j)) { ++cnt; v2.push_back(j); } } if (cnt > n) continue; int setnum = v2.size(); // printf("setnum : %d\n", setnum); // for (int j = 0; j < setnum; ++j) printf("%d ", v[v2[j]].second); ans1 = lca(); LL ans2 = 0; for (int j = 1; j < (1 << setnum); ++j) { int sum = 0, cnt1 = 0; for (int k = 0; k < setnum; ++k) { if (j & (1 << k)) { ++cnt1; sum += v[v2[k]].second; } } // printf("sum %d\n", sum); if ((setnum - cnt1) & 1) ans2 = (ans2 + MOD - (LL)qpow(sum, n)) % MOD; else ans2 = (ans2 + (LL)qpow(sum, n)) % MOD; } ans1 = (ans1 * ans2) % MOD; ans = (ans + ans1) % MOD; } printf("%I64d\n", ans); } int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); int T; scanf("%d", &T); while (scanf("%d", &n) != EOF) work(); return 0; }
相关文章推荐
- ●HDU 6021 MG loves string
- hdu 6021 MG loves string
- HDU 6021 MG loves string(容斥原理)——BestCoder Round #93 1003
- 【HDU 6021】 MG loves string (枚举+容斥原理)
- hdu 6020 MG loves apple 恶心模拟
- HDU 6020 MG loves apple
- 【HDU 6020】 MG loves apple (乱搞?)
- HDU 6020 MG loves apple
- HDU 6019 MG loves gold
- HDU-6019 MG loves gold
- hdu6021[BestCoder #93] MG loves string
- 大数删除k位是否能整除3,MG loves apple(HDU)
- HDU - 6019 ——MG loves gold
- HDU - 6020 MG loves apple (贪心+思维+模拟)
- HDU 6019 MG loves gold
- hdu 6019 MG loves gold
- HDU6021 MG loves string 【容斥定理】
- HDU-3736(KMP_循环节)
- hdu Count the string(KMP)
- [KMP-NEXT数组特性]HDU 3336 Count the string