题目大意:
(维基百科)冒泡排序时一种简单的排序算法,它重复对序列进行扫描并不停检查相邻量元素是否符合大小顺序,如果不符合就交换它们,直到不需要交换位置(便停止扫描,表示排序的终止),该算法因升序排列中每次扫描都将最小的元素交换至前面而得名(就如同泡泡从水底浮至水面一样),因为它只通过比较进行排序,因此它是一种比较排序法。
该算法复杂度为O(n^2),假设经过T论扫描序列刚好称为升序序列(每一轮都有交换,无需交换时不用扫描),则称T为冒泡排序扫描数,例如:
First Round:
( 5 1 4 2 8 ) -> ( 1 5 4 2 8 ), Compares the first two elements, and swaps them.
( 1 5 4 2 8 ) -> ( 1 4 5 2 8 ), Swap since 5 > 4
( 1 4 5 2 8 ) -> ( 1 4 2 5 8 ), Swap since 5 > 2
( 1 4 2 5 8 ) -> ( 1 4 2 5 8 ), since these elements are already in order (8 > 5), algorithm does not swap them.
Second Round:
( 1 4 2 5 8 ) -> ( 1 4 2 5 8 )
( 1 4 2 5 8 ) -> ( 1 2 4 5 8 ), Swap since 4 > 2
( 1 2 4 5 8 ) -> ( 1 2 4 5 8 )
( 1 2 4 5 8 ) -> ( 1 2 4 5 8 )
T = 2
ZX在算法课上学习了冒泡排序,并且老师留给他回家作业,给定一已经升序排列的序列A(共有N个互不相同的元素),并且已经得知该序列是刚好通过K论冒泡排序得到的,现问可能的初始序列有多少种情况。
现有多个测例(测例数量题中给出),每个测例中都会给出N和K(1 ≤ N ≤ 1,000,000,0 ≤ K ≤ N - 1),对于每个测例都给出可能的所有初始序列的总数,由于数据过大,将最后结果模除20100713。
注释代码:
//关于模除的几个公式:
//(1) (a1 × a2 × a3....× an) mod k = (((...(((((a1 mod k) × a2) mod k) × a3) mod k)...an-1) mod k) × an) mod k
//(2) (a - b) mod k = ( ((a mod k) + k) - (b mod k) ) mod k
//(3) (a × b) mod k = ( (a mod k) × (b mod k) ) mod k
//此题中刚好扫描k次就等价于数列中元素的逆序数最大为k
//并且第i号元素的逆序数为[0, i - 1]
//因此根据排列组合知识可得总的初始状态可能为:
//( k! × ((k + 1)^(n - k) - k^(n - k)) ) mod 20100713
//k! mod MOD由(1)算出
//(a^b) mod MOD由(2)在配合二分法算出(mulmod函数)
//k! mod MOD的结果和(a^b) mod MOD的结果由(3)合并
//最后的减法部分(a - b) mod MOD由(2)算出,最终得到答案
/*
* Problem ID : POJ 3761 Bubble Sort
* Author : Lirx.t.Una
* Language : C
* Run Time : 469 ms
* Run Memory : 8000 KB
*/
#include <stdio.h>
#define MOD 20100713LL
//maximum k
#define MAXK 1000000
typedef long long dlong;
dlong fac[MAXK];//factorial阶乘,fac[i]存放i! mod MOD的结果
dlong
mulmod( dlong a, dlong n ) {//multiply mod
//计算乘方取模,a为底数,n为指数
dlong ans;
ans = 1;
while ( n ) {
if ( n & 1LL ) {//二分法,当n为奇时乘模一次
ans *= a;
ans %= MOD;
}
//剩下的情况或者是奇数处理过一次后就都是偶数的形式了
a *= a;//底数平方一次
a %= MOD;//再取模,这样复杂度降为log(N)
n >>= 1LL;//注意,这里需要二分,即除以2
}
return ans;
}
int
main() {
int t;
dlong n, k;
dlong ans1, ans2, ans;
int i;
fac[0] = 1;
fac[1] = 1;
for ( i = 2; i < MAXK; i++ )
fac[i] = fac[i - 1] * i % MOD;
scanf("%d", &t);
while ( t-- ) {
scanf("%lld%lld", &n, &k);
if ( !k ) {
puts("1");
continue;
}
//(1)
ans1 = fac[k];
ans2 = fac[k];
ans1 *= mulmod( k + 1, n - k );//(1) + 二分
ans1 %= MOD;//(3)
ans2 *= mulmod( k, n - k );//(1) + 二分
ans2 %= MOD;//(3)
//(2)
ans1 += MOD;
ans = ( ans1 - ans2 ) % MOD;
printf("%lld\n", ans);
}
return 0;
}
无注释代码:
#include <stdio.h>
#define MOD 20100713LL
#define MAXK 1000000
typedef long long dlong;
dlong fac[MAXK];
dlong
mulmod( dlong a, dlong n ) {
dlong ans;
ans = 1;
while ( n ) {
if ( n & 1LL ) {
ans *= a;
ans %= MOD;
}
a *= a;
a %= MOD;
n >>= 1LL;
}
return ans;
}
int
main() {
int t;
dlong n, k;
dlong ans1, ans2, ans;
int i;
fac[0] = 1;
fac[1] = 1;
for ( i = 2; i < MAXK; i++ )
fac[i] = fac[i - 1] * i % MOD;
scanf("%d", &t);
while ( t-- ) {
scanf("%lld%lld", &n, &k);
if ( !k ) {
puts("1");
continue;
}
ans1 = fac[k];
ans2 = fac[k];
ans1 *= mulmod( k + 1, n - k );
ans1 %= MOD;
ans2 *= mulmod( k, n - k );
ans2 %= MOD;
ans1 += MOD;
ans = ( ans1 - ans2 ) % MOD;
printf("%lld\n", ans);
}
return 0;
}
单词解释:
bubble:n, 气泡,泡沫
sorting:n, 排序
step through:vt, 单步调试,逐句通过
repeat:vt, 重复,背诵
repeatedly:adv, 重复地,再三地
adjacent:adj, 邻接的,毗连的
sorted:adj, 排好序的,分好类的
comparison:n, 比较,对照