Monthly Archives: August 2015

hihoCoder 1133-二分·二分查找之k小数

hihoCoder 1133-二分·二分查找之k小数 #1133 : 二分·二分查找之k小数 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在上一回里我们知道Nettle在玩《艦これ》,Nettle的镇守府有很多船位,但船位再多也是有限的。Nettle通过捞船又出了一艘稀有的船,但是已有的N(1≤N≤1,000,000)个船位都已经有船了。所以Nettle不得不把其中一艘船拆掉来让位给新的船。Nettle思考了很久,决定随机选择一个k,然后拆掉稀有度第k小的船。 已知每一艘船都有自己的稀有度,Nettle现在把所有船的稀有度值告诉你,希望你能帮他找出目标船。 提示:非有序数组的二分查找之二 输入 第1行:2个整数N,k。N表示数组长度, 第2行:N个整数,表示a[1..N],保证不会出现重复的数,1≤a[i]≤2,000,000,000。 输出 第1行:一个整数t,表示t在数组中是第k小的数,若K不在数组中,输出-1。 样例输入 10 4 1732 4176 2602 6176 1303 6207 3125 1 1011 6600 样例输出 1732


给定一个无序序列,问序列中第k小的数是哪个。简单粗暴的方法是排序直接取a[k],复杂度为O(nlgn);还有一种O(lgn)的方法,采用了和hihoCoder 1128-二分·二分查找类似的方法,将序列不断二分成小于某个数和大于某个数的两部分,直到某一部分长度为k。 完整代码如下: [cpp] #include<iostream> #include<cstdio> #include<vector> using namespace std; int n, k; vector<int> a; int GetNumberK(int p, int q) { int m = a[p], i = p, j = q; while (i < j) { while (i < j&&a[j] > m) j–; a[i] = a[j]; while (i < j&&a[i] < m) i++; a[j] = a[i]; } if (k == i + 1)//(1) return m; else if (k < i + 1) return GetNumberK(p, i – 1); else { //k = k – (i – p + 1);//(2),因为(1)处判等的时候i取p,但分割之后p并没有从0开始,所以k还是k return GetNumberK(i + 1, q); } } int main() { //freopen("input.txt", "r", stdin); scanf("%d %d", &n, &k); a.resize(n); for (int i = 0; i < n; i++) scanf("%d", &a[i]); if (k > n||k < 1) printf("-1\n"); else printf("%d\n", GetNumberK(0, n – 1)); return 0; } [/cpp] 本代码提交AC,用时69MS,内存3MB。 需要注意一点,代码中(2)不能出现,虽然递归在[i+1,q]内部查找第k – (i – p + 1)小的数,但是(1)处判等的时候,使用的i(即p)是相对[0,n-1]长度的,所以这里的k不需要剪短]]>

hihoCoder 1128-二分·二分查找

hihoCoder 1128-二分·二分查找 #1128 : 二分·二分查找 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Nettle最近在玩《艦これ》,因此Nettle收集了很多很多的船(这里我们假设Nettle氪了很多金,开了无数个船位)。去除掉重复的船之后,还剩下N(1≤N≤1,000,000)种不同的船。每一艘船有一个稀有值,任意两艘船的稀有值都不相同,稀有值越小的船越稀有,价值也就越高。 Nettle现在通过大建又造出了一艘船,他想知道这艘船是不是重复的。如果是重复的,那么这艘船在Nettle所有的船里面稀有值排多少位。 问题一 Nettle已经先把自己所有船按照稀有值从小到大排列好了(a[1..N]),我们要做的是看看新得到的船(假设稀有值为K)是否在这个序列中,且有对应的a[i]=K时,i为多少? 提示一:有序数组的二分查找 问题二 因为Nettle的船太多了,他不愿意去给所有船按照稀有值排序,而是直接告诉了我们每一艘船的稀有值。在这种情况下我们该如何解决这个问题呢? 提示二:非有序数组的二分查找 输入 第1行:2个整数N,K。N表示数组长度,K表示需要查找的数; 第2行:N个整数,表示a[1..N],保证不会出现重复的数,1≤a[i]≤2,000,000,000。 输出 第1行:一个整数t,表示K在数组中是第t小的数,若K不在数组中,输出-1。 样例输入 10 5180 2970 663 5480 4192 4949 1 1387 4428 5180 2761 样例输出 9


给出一串数字,问某个数字K在该序列中是第几小的。 最简单的解法,遍历一遍数组,找出比K小的数的个数n,则K是第n+1小的数。完整代码如下: [cpp] #include<iostream> #include<cstdio> #include<vector> using namespace std; vector<int> a; int n, k; int main() { scanf("%d %d", &n, &k); a.resize(n); bool is_exist = false; int ans = 0; for (int i = 0; i < n; i++) { scanf("%d", &a[i]); if (a[i] == k) is_exist = true; if (a[i] < k) ans++; } if (!is_exist) printf("-1\n"); else printf("%d\n", ans + 1); return 0; } [/cpp] 本代码提交AC,用时58MS,内存3MB。 但是题意显然不是用这种方法,为了配合下一题的求第k小数,提示使用快排的中间步骤,依次将序列划分成比某个数大和比某个数小的两部分,再在其中某个子序列中递归求解。完整代码如下: [cpp] #include<iostream> #include<cstdio> #include<vector> using namespace std; vector<int> a; int n, k; int GetOrder(int p, int q) { int m = a[p]; int i = p, j = q; while (i < j) { while (i < j&&a[j] > m) j–; a[i] = a[j]; while (i < j&&a[i] < m) i++; a[j] = a[i]; } if (k == m) return i; else if (k < m) return GetOrder(p, i – 1); else return GetOrder(i + 1, q); } int main() { //freopen("input.txt", "r", stdin); scanf("%d %d", &n, &k); a.resize(n); bool is_exist = false; for (int i = 0; i < n; i++) { scanf("%d", &a[i]); if (a[i] == k) is_exist = true; } if (!is_exist) printf("-1\n"); else printf("%d\n", GetOrder(0, n – 1) + 1); return 0; } [/cpp] 本代码提交AC,用时57MS,内存3MB。]]>

HDOJ 5417-Victor and Machine

HDOJ 5417-Victor and Machine Victor and Machine Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 177 Accepted Submission(s): 91 Problem Description Victor has a machine. When the machine starts up, it will pop out a ball immediately. After that, the machine will pop out a ball every w seconds. However, the machine has some flaws, every time after x seconds of process the machine has to turn off for y seconds for maintenance work. At the second the machine will be shut down, it may pop out a ball. And while it’s off, the machine will pop out no ball before the machine restart. Now, at the 0 second, the machine opens for the first time. Victor wants to know when the n-th ball will be popped out. Could you tell him? Input The input contains several test cases, at most 100 cases. Each line has four integers x, y, w and n. Their meanings are shown above。 1≤x,y,w,n≤100. Output For each test case, you should output a line contains a number indicates the time when the n-th ball will be popped out. Sample Input 2 3 3 3 98 76 54 32 10 9 8 100 Sample Output 10 2664 939 Source BestCoder Round #52 (div.2) Recommend hujie | We have carefully selected several similar problems for you: 5421 5420 5419 5418 5416


有两种解法,一模拟,二推导公式。我采用的是第二种方法,根据x和w的大小关系,分为3种情况。 当w>x时,只可能启动的时候弹出小球,相邻两球弹出的时间间隔为x+y,因为0时刻会弹出一个球,所以总时间为(n-1)*(x+y)。 当w==x时,每隔(x+y)弹出2球,如果n为奇数,n-1为偶数,则需要花(n-1)/2*(x+y)时间,这里n-1减去了0时刻那个球,因为那个球不花时间;如果n为偶数,n-1为奇数,代入上式为(n-2)/2*(x+y),但是这里的n-1减去了一个球,最后还要隔x时间才弹出一个球,所以还需加上x,即(n-2)/2*(x+y)+x。 当w<x时,每x+y时间会弹出num=x/w+1个球,如果n不能整除num,则n/num是int型,即有n/num个完整的周期,还剩下n%num个球没弹出来,因为每个w时间弹一个球,所以只需间隔n%num-1次就可弹出n%num个球,总时间为(n/num)*(x+y)+(n%num-1)*w;如果n能整除num,则有n/num个完整的周期,我们先算前n/num-1个周期,时间为(n/num-1)*(x+y),最后一个周期,因为机器开启时刻会弹出一个球,所以只需间隔num-1次即可弹出这个周期剩余的球,加上w*(num-1)。 完整代码如下: [cpp] #include<iostream> #include<cstdio> using namespace std; int main() { int x, y, w, n; while (scanf("%d %d %d %d", &x, &y, &w, &n) != EOF) { if (w > x) printf("%d\n", (n – 1)*(x + y)); else if (w == x) { if (n & 1) printf("%d\n", ((n – 1) / 2)*(x + y)); else printf("%d\n", ((n – 2) / 2)*(x + y) + x); } else { int num = x / w + 1; if (n % num == 0) printf("%d\n", (n / num – 1)*(x + y) + w * (num – 1)); else printf("%d\n", (n / num)*(x + y) + (n % num – 1) * w); } } return 0; } [/cpp] 本代码提交AC,用时0MS,内存1560K。]]>

hihoCoder 1124-好矩阵

hihoCoder 1124-好矩阵 #1124 : 好矩阵 时间限制:3000ms 单点时限:1000ms 内存限制:256MB 描述 给定n, m。一个n × m矩阵是好矩阵当且仅当它的每个位置都是非负整数,且每行每列的和 ≤ 2。求好矩阵的个数,模$$10^9$$ + 7 输入 第一行一个整数T,表示测试点个数。下面T个测试点。每个测试点一行,包含两个整数n,m。1 ≤ T ≤ $$10^4$$. 1 ≤ n, m ≤ 100. 输出 T行。每行是对应测试点的答案。 样例输入 1 2 2 样例输出 26


这一题的题意也很明确,如果是单个测试数据,可以考虑用DFS,但是本题测试数据最多有$$10^4$$,当n和m不同时,DFS的结果不能复用,所以超时妥妥的。 要想中间结果复用,一定是DP,所以考虑用DP来做,我是参考了题解此博客。 完整代码如下: [cpp] #include<iostream> #include<cstdio> using namespace std; const int kMaxMN = 105, kMod = 1000000007; typedef long long ll; ll f[kMaxMN][kMaxMN][kMaxMN]; ll ans[kMaxMN][kMaxMN]; void Init() { for (int m = 1; m < kMaxMN; m++) { for (int n = 0; n < kMaxMN; n++) for (int a = 0; a <= m; a++) for (int b = 0; a + b <= m; b++) f[n][a][b] = 0; f[0][m][0] = 1; for (int n = 1; n < kMaxMN; n++) { //f[n][m][0] = 1;//如果f[n-1][m][0]=0,即不存在全为0的情况,则f[n][m][0]不等于1而是等于0 for (int a = 0; a <= m; a++) { for (int b = 0; a + b <= m; b++) { f[n][a][b] += f[n – 1][a][b];//(1) f[n][a][b] %= kMod; if (a > 0) { //(2.1) f[n][a – 1][b + 1] += (ll)a*f[n – 1][a][b]; f[n][a – 1][b + 1] %= kMod; //(4) f[n][a – 1][b] += (ll)a*f[n – 1][a][b]; f[n][a – 1][b] %= kMod; } if (b > 0)//(2.2) { f[n][a][b – 1] += (ll)b*f[n – 1][a][b]; f[n][a][b – 1] %= kMod; } if (a > 1)//3.1 { f[n][a – 2][b + 2] += (ll)(a*(a – 1) / 2)*f[n – 1][a][b]; f[n][a – 2][b + 2] %= kMod; } if (a > 0 && b > 0)//3.2 { f[n][a – 1][b] += (ll)a*(ll)b*f[n – 1][a][b]; f[n][a – 1][b] %= kMod; } if (b > 1)//3.3 { f[n][a][b – 2] += (ll)(b*(b – 1) / 2)*f[n – 1][a][b]; f[n][a][b – 2] %= kMod; } } } ans[n][m] = 0; for (int a = 0; a <= m; a++) { for (int b = 0; a + b <= m; b++) { ans[n][m] += f[n][a][b]; ans[n][m] %= kMod; } } } } } int main() { Init(); int t,n,m; scanf("%d", &t); while (t–) { scanf("%d %d", &n, &m); printf("%lldn", ans[n][m]); } return 0; } [/cpp] 转换情况较多,代码和题解对照查看。 本代码提交AC,用时1698MS,内存9MB。]]>

hihoCoder 1123-好配对

hihoCoder 1123-好配对 #1123 : 好配对 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 给定两个序列a和b,每个序列中可能含有重复的数字。 一个配对(i,j)是一个好配对当从第一个序列中选出一个数ai,再从第二个序列中选出一个数bj且满足ai>bj。 给出两个序列,问存在多少个好配对。 输入 输入包含多组数据,数据第一行一个整数T,表示数据组数。(T<=5) 每组数据第一行包含两个整数n和m。(0<n,m<=$$10^5$$) 接下来n行,每行两个整数x和y,表示在第一个序列中有y个x。 接下来m行,每行两个整数x和y,表示在第二个序列中有y个x。(0<x<=$$10^9$$,0<y<=$$10^4$$) 输出 对于每组数据,输出一行一个整数,表示好配对的数量 样例输入 1 2 2 3 2 4 1 3 1 2 3 样例输出 10


此题最先想到的解法是类似桶排序的思路,用空间来换时间,但是看到x的范围是$$10^9$$,显然不行,于是牺牲时间来换空间,构造: [cpp] typedef struct Ele { int value; int num; bool operator < (const Ele& e) const { return value < e.value; } }; [/cpp] 依次输入两个序列,并按value从小到大排序;两个序列从头开始遍历,计算好配对的个数。 完整代码如下: [cpp] #include<iostream> #include<cstdio> #include<vector> #include<algorithm> using namespace std; typedef struct Ele { int value; int num; bool operator < (const Ele& e) const { return value < e.value; } }; vector<Ele> first_seq, second_seq; int main() { int t,m,n,x,y; long long ans; scanf("%d", &t); while (t–) { scanf("%d %d", &n, &m); first_seq.clear(); first_seq.resize(n); second_seq.clear(); second_seq.resize(m); for (int i = 0; i < n; i++) scanf("%d %d", &first_seq[i].value, &first_seq[i].num); for (int i = 0; i < m; i++) scanf("%d %d", &second_seq[i].value, &second_seq[i].num); sort(first_seq.begin(), first_seq.end()); sort(second_seq.begin(), second_seq.end()); ans = 0; int i = 0, j = 0; long long sum2 = 0; while (i < n && j < m) { while (j < m && second_seq[j].value < first_seq[i].value) { sum2 += second_seq[j].num; j++; } ans += (first_seq[i].num*sum2); i++; } while (i < n) { ans += (first_seq[i].num*sum2); i++; } printf("%lldn", ans); } return 0; } [/cpp] 本代码提交AC,用时193MS,内存11MB。]]>

HDOJ 5392-Infoplane in Tina Town

HDOJ 5392-Infoplane in Tina Town Infoplane in Tina Town Time Limit: 14000/7000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others) Total Submission(s): 1636 Accepted Submission(s): 385 Problem Description There is a big stone with smooth surface in Tina Town. When people go towards it, the stone surface will be lighted and show its usage. This stone was a legacy and also the center of Tina Town’s calculation and control system. also, it can display events in Tina Town and contents that pedestrians are interested in, and it can be used as public computer. It makes people’s life more convenient (especially for who forget to take a device). Tina and Town were playing a game on this stone. First, a permutation of numbers from 1 to n were displayed on the stone. Town exchanged some numbers randomly and Town recorded this process by macros. Town asked Tine,”Do you know how many times it need to turn these numbers into the original permutation by executing this macro? Tina didn’t know the answer so she asked you to find out the answer for her. Since the answer may be very large, you only need to output the answer modulo 3∗230+1=3221225473 (a prime). Input The first line is an integer T representing the number of test cases. T≤5 For each test case, the first line is an integer n representing the length of permutation. n≤3∗106 The second line contains n integers representing a permutation A1…An. It is guaranteed that numbers are different each other and all Ai satisfies ( 1≤Ai≤n ). Output For each test case, print a number ans representing the answer. Sample Input 2 3 1 3 2 6 2 3 4 5 6 1 Sample Output 2 6 Source BestCoder Round #51 (div.2) Recommend hujie | We have carefully selected several similar problems for you: 5395 5394 5393 5390 5389


此题和POJ 2369-Permutations类似,只是测试样例更多,数据规模更大,最后还要对某个大数取模。所以在求所有循环节长度的最小公倍数的时候,不能使用gcd转换的方法,需要先后使用因式分解和快速幂算法。 参考下面的例子理解分解质因数法求最小公倍数的方法。 60=2×2×3×5 18=2×3×3 lcm(60,18)=180=2×2×3×3×5 通过观察可以看出规律,要求a,b的最小公倍数,先将a和b分解成质因数相乘的形式,对于每一个质因子x,取x在a和b中出现频率最高的数作为x在最小公倍数中的频率。比如2在60中出现2次,但在18中只出现1次,所以2在最小公倍数180中也出现2次,同理质因子3和5分别出现2次和1次。 假设某个质因子x出现y次,则最后要计算$$x^ymodp$$,可以使用快速幂方法提高速度,该方法很好理解,将y看成二进制形式,如果y为偶数,则$$x^y=(x*x)^{y/2}$$;如果y为奇数,则$$x^y=x*x^{y-1}$$,y-1就是偶数了。同时modp就是快速幂取模了。 完整代码如下: [cpp] #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef unsigned long long ULL; const int kMaxN = 3000005, kNumPrime = 269; const ULL kMod = 3221225473; bool visited[kMaxN]; int permutation[kMaxN]; int prime[kNumPrime] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723 }; int prime_times[kMaxN]; //求x的所有质因子及其频率 void GetPrimeFactor(int x) { for (int i = 0; i < kNumPrime; i++) { int tmp = 0; while (x%prime[i] == 0) { tmp++; x /= prime[i]; } if (tmp > prime_times[prime[i]]) prime_times[prime[i]] = tmp; if (x == 1) return; } prime_times[x]++; } //快速幂取模x^ymod(kMod) ULL QuickPow(ULL x, ULL y) { ULL ans = 1; while (y) { if (y & 1) ans = (ans*x)%kMod; x = (x*x) % kMod; y >>= 1; } return ans; } int main() { int t, n, len; ULL ans; scanf("%d", &t); while (t–) { scanf("%d", &n); memset(visited, false, kMaxN); memset(prime_times, 0, kMaxN); for (int i = 1; i <= n; i++) scanf("%d", &permutation[i]); for (int i = 1; i <= n; i++) { if (!visited[i]) { visited[i] = true; int j = permutation[i]; len = 1; while (j != i) { visited[j] = true; j = permutation[j]; len++; } GetPrimeFactor(len); } } ans = 1; for (int i = 2; i < n; i++) if (prime_times[i] != 0) ans = (ans*QuickPow(i, prime_times[i])) % kMod; printf("%I64un", ans); } return 0; } [/cpp] 本代码提交AC,用时5101MS,内存27984K。]]>

HDOJ 5391-Zball in Tina Town

HDOJ 5391-Zball in Tina Town Zball in Tina Town Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 817 Accepted Submission(s): 471 Problem Description Tina Town is a friendly place. People there care about each other. Tina has a ball called zball. Zball is magic. It grows larger every day. On the first day, it becomes 1 time as large as its original size. On the second day,it will become 2 times as large as the size on the first day. On the n-th day,it will become n times as large as the size on the (n-1)-th day. Tina want to know its size on the (n-1)-th day modulo n. Input The first line of input contains an integer T, representing the number of cases. The following T lines, each line contains an integer n, according to the description. T≤$$10^5$$,2≤n≤$$10^9$$ Output For each test case, output an integer representing the answer. Sample Input 2 3 10 Sample Output 2 Source BestCoder Round #51 (div.2) Recommend hujie | We have carefully selected several similar problems for you: 5395 5394 5393 5392 5390  


本题关键在于理解题意,在BestCoder中文描述中是第n天变大n倍,这样不就是n+1倍了吗,当时一直按这个思路,以为是A176787这个序列,后来看英文以及别人的解释才明白。
On the n-th day,it will become n times as large as the size on the (n-1)-th day.
所以第n天的大小就是第n-1天的n倍,也就是n!。 最终结果即为$$(n-1)!modn$$,如果n为合数,n一定能分解成n以内的某些个数相乘,所以结果为0;如果n为素数,根据威尔逊定理,有 所以结果为$$-1modn=n-1$$。 当n=2和4时,需要特殊处理。完整代码如下: [cpp] #include<iostream> #include<cstdio> using namespace std; bool IsPrime(int x) { for (int i = 2; i*i <= x; i++) if (x%i == 0) return false; return true; } int main() { int t, n; scanf("%d", &t); while (t–) { scanf("%d", &n); if (n == 2) printf("1n"); else if (n == 4) printf("2n"); else if (IsPrime(n)) printf("%dn", n – 1); else printf("0n"); } return 0; } [/cpp] 本代码提交AC,用时967MS,内存1576K。]]>

POJ 2369-Permutations

POJ 2369-Permutations Permutations Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 2792 Accepted: 1473 Description We remind that the permutation of some final set is a one-to-one mapping of the set onto itself. Less formally, that is a way to reorder elements of the set. For example, one can define a permutation of the set {1,2,3,4,5} as follows: This record defines a permutation P as follows: P(1) = 4, P(2) = 1, P(3) = 5, etc. What is the value of the expression P(P(1))? It’s clear, that P(P(1)) = P(4) = 2. And P(P(3)) = P(5) = 3. One can easily see that if P(n) is a permutation then P(P(n)) is a permutation as well. In our example (believe us) It is natural to denote this permutation by P2(n) = P(P(n)). In a general form the defenition is as follows: P(n) = P1(n), Pk(n) = P(Pk-1(n)). Among the permutations there is a very important one — that moves nothing: It is clear that for every k the following relation is satisfied: (EN)k = EN. The following less trivial statement is correct (we won’t prove it here, you may prove it yourself incidentally): Let P(n) be some permutation of an N elements set. Then there exists a natural number k, that Pk = EN. The least natural k such that Pk = EN is called an order of the permutation P. The problem that your program should solve is formulated now in a very simple manner: “Given a permutation find its order.” Input In the first line of the standard input an only natural number N (1 <= N <= 1000) is contained, that is a number of elements in the set that is rearranged by this permutation. In the second line there are N natural numbers of the range from 1 up to N, separated by a space, that define a permutation — the numbers P(1), P(2),…, P(N). Output You should write an only natural number to the standard output, that is an order of the permutation. You may consider that an answer shouldn’t exceed 109. Sample Input 5 4 1 5 2 3 Sample Output 6 Source Ural State University Internal Contest October’2000 Junior Session


有一个序列和一个置换T,问对这个序列置换多少次能恢复成原来的序列。这其实就是求置换群T的秩k使得$$T^k=e$$,e为单位置换f(x)=x。 在离散数学中有一个定理,k等于T中所有循环节长度的最小公倍数。 比如题中的P(n)有1->4->2->1,则循环节长度就为3,以及3->5->3,循环节长度为2,则最小公倍数为lcm(3,2)=6,即k=6。 设x,y的最小公倍数为lcm(x,y),最大公约数为gcd(x,y),则有gcd(x, y)×lcm(x, y) = xy,挺神奇的,所以求最小公倍数可以转换为求最大公约数。 完整代码如下: [cpp] #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstdio> using namespace std; const int kMaxN = 1005; bool visited[kMaxN]; int permutation[kMaxN]; //最大公约数 int gcd(int x, int y) { int tmp; while (y) { tmp = y; y = x % y; x = tmp; } return x; } int main() { int n,ans,len; while (scanf("%d", &n)!=EOF) { ans = 1; memset(visited, false, n + 1); for (int i = 1; i <= n; i++) scanf("%d", &permutation[i]); for (int i = 1; i <= n; i++) { if (!visited[i]) { visited[i] = true; int j = permutation[i]; len = 1; while (j!=i) { visited[j] = true; j = permutation[j]; len++; } ans = len*ans/gcd(ans, len);//gcd(a, b)×lcm(a, b) = ab } } printf("%dn", ans); } return 0; } [/cpp] 本代码提交AC,用时0MS,内存136K。]]>

hihoCoder week 59-1-Performance Log

hihoCoder week 59-1-Performance Log 题目1 : Performance Log 时间限制:8000ms 单点时限:1000ms 内存限制:256MB 描述 You are given a txt file, which is performance logs of a single-threaded program. Each line has three columns as follow: [Function Name] [TimeStamp] [Action] [FunctionName] is a string of length between 1~255 [TimeStamp] format is hh:mm:ss Valid values for “Action” column are START or END, marking the start or end of a function call. Each function will only be called once. Output the depth-first traversal result of the call graph with the total time of each function call. However, sometimes the performance log isn’t correct and at that time you just need to output “Incorrect performance log”. 输入 The input only contains 1 case, first line is a positive number N representing the number of logs(1 <= N <= 20000), then there are N lines in next, each line is the log info containing [Function Name] [TimeStamp] [Action], [Function Name] is a string, you can assume the [Function Name] is distinct and the length between 1~255. 输出 Output the depth-first traversal result of the call graph with the total time of each function call for the correct performance, or output “Incorrect performance log”. 提示 A call graph is a directed graph that represents calling relationships between subroutines in a computer program. Call graph for the sample input is shown as below: Another sample test case.

Sample Input Sample Output
8 FuncA 00:00:01 START FuncB 00:00:02 START FuncC 00:00:03 START FuncA 00:00:04 END FuncB 00:00:05 END FuncD 00:00:06 START FuncD 00:00:07 END FuncC 00:00:08 END Incorrect performance log
样例输入 8 FuncA 00:00:01 START FuncB 00:00:02 START FuncC 00:00:03 START FuncC 00:00:04 END FuncB 00:00:05 END FuncD 00:00:06 START FuncD 00:00:07 END FuncA 00:00:08 END 样例输出 FuncA 00:00:07 FuncB 00:00:03 FuncC 00:00:01 FuncD 00:00:01
本题要判断一个程序的函数调用关系是否合法。需要考虑一下几点: 1. 序列时间必须递增(经测试无需严格递增) 2. START必须在END的前面 3. 函数调用关系不能交叉,比如ABCBCA就不行,因为B调用了C,但C没结束B就结束了,对于单线程程序,显然不行 4. 因为是单线程程序,主函数A的开始和结束要是log的第一条和最后一条。 对于第3点,可以借助堆栈完成。完整代码如下: [cpp] #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string> #include<stack> #include<map> #include<vector> #include<cstdio> using namespace std; typedef struct one_log { string name; int sec; }; void sec2str(int sec) { int hh = sec / 3600; int mm = (sec – hh * 3600) / 60; int ss = sec – hh * 3600 – mm * 60; printf("%02d:%02d:%02dn", hh, mm, ss); } int main() { freopen("input.txt", "r", stdin); int n; stack<one_log> logs; string function_name, start_end,first_name,last_name; int hh, mm, ss; char tmp_c; vector<string> seq; map<string, int> ans; bool is_correct = true; scanf("%d", &n); for (int t = 0; t < n;t++) { cin >> function_name >> hh >> tmp_c >> mm >> tmp_c >> ss >> start_end; if (t == 0) first_name = function_name; if (t == n – 1) last_name = function_name; if (!is_correct) continue; one_log l; l.name = function_name; l.sec = hh * 3600 + mm * 60 + ss; if (start_end == "START") { logs.push(l); seq.push_back(l.name); } else { one_log tmp = logs.top(); //if (l.sec <= tmp.sec) if (l.sec < tmp.sec)//不是“严格”递增的。 { is_correct = false; continue; } if (tmp.name == l.name) { ans[l.name] = l.sec – tmp.sec; logs.pop(); } else logs.push(l); } } if (!is_correct||!logs.empty()||first_name!=last_name) printf("Incorrect performance logn"); else { for (int i = 0; i < seq.size(); i++) { printf("%s ", seq[i].c_str()); sec2str(ans[seq[i]]); } } return 0; } [/cpp] 本代码提交AC,用时61MS,内存2MB。]]>

hihoCoder week 58-1-Beautiful String

hihoCoder week 58-1-Beautiful String 题目1 : Beautiful String 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 We say a string is beautiful if it has the equal amount of 3 or more continuous letters (in increasing order.) Here are some example of valid beautiful strings: “abc”, “cde”, “aabbcc”, “aaabbbccc”. Here are some example of invalid beautiful strings: “abd”, “cba”, “aabbc”, “zab”. Given a string of alphabets containing only lowercase alphabets (a-z), output “YES” if the string contains a beautiful sub-string, otherwise output “NO”. 输入 The first line contains an integer number between 1 and 10, indicating how many test cases are followed. For each test case: First line is the number of letters in the string; Second line is the string. String length is less than 10MB. 输出 For each test case, output a single line “YES”/”NO” to tell if the string contains a beautiful sub-string. 提示 Huge input. Slow IO method such as Scanner in Java may get TLE. 样例输入 4 3 abc 4 aaab 6 abccde 3 abb 样例输出 YES NO YES NO


本题考察字符串的基本知识。题目给出了漂亮字符串的定义,形如aa…bb…cc,保证至少3个连续升序的字符串,并且每个字符的个数相同。仔细观察可以发现,虽然aaaabbccc不是漂亮字符串,但其子串aabbcc是漂亮的,所以只要保证b的数量小于等于a和c的数量即可。 所以解法就是遍历字符串,计算每个字符重复出现的次数,判断连续3种字符是否为连续升序,且满足中间字符数量大于两边。算法复杂度为O(N)。 完整代码如下: [cpp] #include<iostream> #include<cstdio> #include<string> using namespace std; const int kMaxN = 10 * 1024 * 1024 + 5; char line[kMaxN]; int n; char same_letter[kMaxN]; int same_length[kMaxN]; bool check(int k) { if ((same_letter[k] – 1 == same_letter[k – 1]) && (same_letter[k – 1] – 1 == same_letter[k – 2])) if (same_length[k – 1] <= same_length[k] && same_length[k – 1] <= same_length[k – 2]) return true; return false; } bool IsBeautiful() { if (n < 3) return false; else { int i = 0,k=0; while (i < n) { int j = i + 1; while (j < n && line[j] == line[i]) j++; same_letter[k] = line[i]; same_length[k] = j – i; if (k >= 2) { if (check(k)) return true; } k++; i = j; } return false; } } int main() { int t; scanf("%d", &t); while (t–) { scanf("%d", &n); scanf("%s", line); if (IsBeautiful()) printf("YESn"); else printf("NOn"); } return 0; } [/cpp] 本代码提交AC,用时293MS,内存37MB。]]>