首页 > ACM题库 > HDU-杭电 > HDU 3148-Code Permutations[解题报告]HOJ
2014
03-06

HDU 3148-Code Permutations[解题报告]HOJ

Code Permutations

问题描述 :


Playfair Cipher

You are soon to graduate from the mathemagician school of Hagworts, and you’re quite content with yourself; all the hard work and elbowing has finally paid off. Being successful at most of your endeavors you would normally end up a herald of sound reasoning and good mathemagics. You, however, are different; not only have you spent your young years secretly hacking away at computers, writing code to do your assigned routine homework for you, but of late you have started planning how to cram all your mathemagical skills into a computer to completely eliminate the need for mathemagicians! To show the others just how great a visionary you are, you plan to make your graduation ceremony something they will never forget.

To do this you need to break into the safe of your arch-nemesis, Hairy Peter. The safe is locked by a code mechanism: All natural numbers from 1 to N need to be typed in in the correct order, set by Hairy Peter. Fortunately you know that Hairy, being a good mathemagician, has a certain weakness; he has a rather unhealthy obsession with the number K. (For instance he always has to introduce himself K times whenever he meets new people, making him quite annoying to be around.) Thus you are certain that his code, when viewed as a permutation of the N first naturals, has order exactly K. (i.e. K is the smallest positive number such that if you K times replace Playfair Cipher with the position of x in Hairy’s code, you end up with the x you started with, for all x. Thus e.g. the order of the permutation corresponding to the code 2 3 1 is 3, as 1 –> 3 –> 2 –> 1 and 2 –> 1 –> 3 –> 2 and 3 –> 2 –> 1 –> 3.) While this does not help you directly, it greatly reduces the number of code inputs you may have to try before you find the correct one. "How many?" is the question you are pondering right now. You must know the exact number, lest you risk preparing too little time for cracking the safe.

Now you also have a certain mathemagical weakness — arguably a bit worse than Hairy Peter’s: Because of your dark scheme to program mathemagical computers, you insist there are no numbers greater than what can be represented by a signed 32-bit integer, namely the prime P = 231 – 1. Of course there must be nothing your computers cannot count. In fact you hate this upper limit P so intensely that you have decided to make a new mathemagics where P equals 0. Ha, take that! (Well, you are quite aware that you are really just counting modulo P, but it will have to suffice until you find better ways of punishing P.) In fact this turns out to be quite an advantage for you! For instance, if the number of code permutations you have to check turns out to be 231, there will actually be just one permutation for you to check, as 231 mod P = 1. (Or at least you think so…) That’s just magnificent!

输入:

The input consists of two integers N (1 <= N <= 100) and K (1 <= K <= 231 – 1) respectively.

输出:

The input consists of two integers N (1 <= N <= 100) and K (1 <= K <= 231 – 1) respectively.

样例输入:

3 2
6 6
15 12

样例输出:

3
240
1789014075

//============================================================================
// Name        : J.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;

typedef long long LL;
const int P = 2147483647;
const int maxn = 101;
map< int, LL > f[ maxn ];
vector< int > fac;
LL c[ maxn ][ maxn ];
int n, m;
LL ff[ maxn ], iv[ maxn ];

int powmod( LL a, int b, int c){
	LL ret = 1;
	while(b){
		if(b & 0x1) ret = ret * a % c;
		a = a * a % c;
		b >>= 1;
	}
	return ret;
}

int gcd(int a, int b) {return b ? gcd( b, a % b) : a; }
inline int lcm( int a, int b){return (a / gcd( a, b)) * b;}

void get_fac( ){
	LL i;
	fac.clear();
	for(i = 1; i * i <= m; ++ i) if(m % i == 0){
		fac.push_back( i );
		if( m / i != i) fac.push_back( m / i );
	}
	sort( fac.begin(), fac.end());
}
void get(){
	scanf("%d%d", &n, &m);
	for(int i = 0; i <= n; ++ i) f[ i ].clear();
}

void work(){
	get_fac();
	f[ 0 ][ 1 ] = 1;
	for(int i = 0; i < fac.size() && fac[ i ] <= n; ++ i) {
		for(int j = n; j >= 0; -- j)
			for(map<int, LL>::iterator p = f[ j ].begin(); p != f[ j ].end(); ++ p) {
				LL cc = 1;
				int cct = 1;
				for(int k = fac[ i ]; j + k <= n; k += fac[ i ], ++ cct) {
					cc = cc * c[n - j - k + fac[ i ]][ fac[ i ]] % P;
					cc = cc * ff[ fac[ i ] - 1 ] % P;
					LL &now = f[ j + k ][ lcm(p -> first, fac[ i ]) ];
					now = (now + (p-> second * cc % P )* iv[ cct ] % P) % P;
				}
			}
	}
	printf("%d\n", (int)f[ n ][ m ]);
}
void pre(){
	int i, j;
	for(i = 0; i < maxn; ++ i) for(j = 0; j <= i; ++ j)
		if(i == 0 || j == 0) c[ i ][ j ] = 1;
		else c[ i ][ j ] = (c[i - 1][ j ] + c[ i - 1][j - 1 ]) % P;
	ff[ 0 ] = 1;
	for(i = 1; i < maxn; ++ i)
		ff[ i ] =ff[i - 1] * i % P;
	iv[ 0 ] = 1;
	for(i = 1; i < maxn; ++ i)
		iv[ i ] = iv[i - 1] * powmod( i, P - 2, P) % P;
}

int main() {
	pre();
	int T;
	cin >> T;
	while(T --){
		get();
		work();
	}
	return 0;
}

  1. bottes vernies blanches

    I appreciate the efforts you men and women place in to share blogs on such sort of matters, it was certainly useful. Keep Posting!

  2. 第二个方法挺不错。NewHead代表新的头节点,通过递归找到最后一个节点之后,就把这个节点赋给NewHead,然后一直返回返回,中途这个值是没有变化的,一边返回一边把相应的指针方向颠倒,最后结束时返回新的头节点到主函数。