Probabilistic Encryption

Description [title]

Shallot students to celebrate the breakthrough title copy number 150, own a probabilistic encryption algorithm. Now shallot students will have a number of N-bit password, a password each and every one of a 1-M. Now random encryption algorithm shallot own will give you the number of M \ (x_i \) , on behalf of each encryption when all becomes a bit i will \ (x_i \) , and when the N-bit password and all become it starts the same time, the encryption algorithm stops. All the given password, and then ask how many times the encryption is a very difficult problem, in order to simplify the problem, assume that we do not know now shallot Password input, the input is a random password for a total of \ (M ^ N) \ possibilities, each possibility probability of bit \ (M ^ {-} N \) . Shallot students wanted to know, in this case, how many times the random password encryption desired needs.

[Input Format]

Two line numbers N, M

M represents the number of down plus line \ (x_i \)

[Output format]

Output line an integer representing the desired number of times multiplied by \ (M ^ N \) mode \ (10 ^ 9 + 7 \) Results

[Sample 1]

2 2

1 2

Output [1]

4

[Sample 2]

2 2

2 1

Output [2]

8

[Agreed] with the scale data

For 40% of the data, \ (N, M \ Leq. 5 \)

For 70% of the data, \ (N, M \ Leq 20 is \)

To 100% of the data, \ (. 1 \ Leq N, M \ Leq 100,. 1 \ Leq x_i \ Leq M \) , to ensure that all \ (X_i \) equal to each other.

Solution

Obviously each answer is the least common multiple of the length of the sequence of the loop section of the entire sequence of each number.

Section cycle length is a number of times to become their own needs.

So how fast calculation of all the circumstances of it?

Obviously enumerate all permutations unrealistic, but found no relationship between each arranged in the order of its answer, only its circulation contains several sections related. So I wanted to be able to enumerate all the possibilities of violence like pressure cycling section of it? Then we look at how many total circulation section.

Assuming that the first section of the cycle number is 1, then 2 cycles of two sections, both of conversion, and then again three, four ...... we found \ (1 + 2 + 3 + ...... + 14 > 100 \) , that is, at most, only 14 kinds of loop section. Because we assume that some sections particularly long cycle, that is to say the cycle section contains a lot of numbers, then the total will be less kind of loop section. It can be up to 14 kinds. At the same time the number of cycles in a cycle section is the same as the equivalent of a circle, each turn a certain angle, when it transferred back to the beginning of time, all points of transfer degree is the same, it can be a consideration.

So we like the pressure of all the permutations, but how statistics every permutation of how many do?

Suppose the current section arranged x cycles, these cycles section contains the number of sum, then several of the current arrangement is \ (SUM ^ N \) , which is obviously wrong, because it is possible that N is the number of election a cyclical festival, but also all minus all arrangement of loop contains two sections, but not for ...... so he found this to be the inclusion-exclusion.

This question then finished it.

#include <iostream>
#include <cstdio>
using namespace std;
inline long long read() {
  long long x = 0; int f = 0; char c = getchar();
  while (c < '0' || c > '9') f |= c == '-', c= getchar();
  while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
  return f ? -x : x;
}

const int mod = 1e9 + 7;
int n, m, x[105], c[105], z[2][105];
bool vis[105];
inline int gcd(int a, int b) {
  if (!b) return a;
  return gcd(b, a % b);
}
inline int mul(int a, int b) {
  int ans = 1;
  while (b) {
    if (b & 1) ans = 1ll * ans * a % mod;
    a = 1ll * a * a % mod; b >>= 1;
  }
  return ans;
}
int main() {
  freopen("prob.in", "r", stdin);
  freopen("prob.out", "w", stdout);
  n = read(); m = read();
  for (int i = 1; i <= m; ++i) x[i] = read();
  for (int i = 1; i <= m; ++i)
    if (!vis[i]) {//计算循环节
      int p = x[i], cnt = 1;
      while (p != i) vis[p] = 1, p = x[p], cnt++;
      vis[i] = 1; c[cnt] += cnt;
    }
  int p = 0;
  for (int i = 1; i <= m; ++i)
    if (c[i])//记录每个循环节的长度以及这个长度的点的个数
      z[0][p] = i, z[1][p] = c[i], p++;
  long long ans = 0;
  for (int i = 1; i < (1 << p); ++i) {//枚举所有情况
    int num_1 = 0, lcm = 1;long long sum = 0;
    for (int j = 0; j < p; ++j)
      if (i & (1 << j)) {//计算有多少种循环节
        num_1++;
        lcm = lcm * z[0][j] / gcd(lcm, z[0][j]);
      }
    for (int j = i; j; j = (j - 1) & i) {//枚举子集
      int num_2 = 0, tot = 0, lcm = 1;
      for (int k = 0; k < p; ++k)
        if (j & (1 << k)) {
          num_2++;
          lcm = lcm * z[0][k] / gcd(lcm, z[0][k]);
          tot += z[1][k];
        }
        //判断子集是加还是减
      if ((num_1 & 1) != (num_2 & 1)) sum = (0ll + sum - mul(tot, n) + mod) % mod;
      else sum = (0ll + sum + mul(tot, n)) % mod;
    }
    ans = (0ll + ans + sum * lcm) % mod;
  }
  printf("%lld\n", ans);
  return 0;
}

Guess you like

Origin www.cnblogs.com/kylinbalck/p/11801588.html