2014 Multi-University Training Contest 7 部分题目解题报告
前两天网络挂了=。= 一直没法发博客。。
HDOJ 4937 Lucky Number
题意:给一个数,问这个数能在多少种进制下只用3456来表示。
分析:很遗憾考场没做出。。其实很简单,分类讨论就可以了,一位的只有3456,二位的就是枚举3456然后解一元一次方程组,三位解一元二次方程组,四位及以上,一想,发现7000^3*3超过1e12了,所以base从4枚举到7000就可以了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 using namespace std; 6 7 int T, cas = 0, ans; 8 long long x; 9 void output() 10 { 11 printf("Case #%d: %d\n", ++cas, ans); 12 } 13 bool ok(long long x, long long base) 14 { 15 int tmp, cnt = 0; 16 while(x){ 17 tmp = x % base; 18 if (tmp < 3 || tmp > 6) return false; 19 x /= base; 20 cnt ++; 21 } 22 if (cnt > 3) return true; 23 return false; 24 } 25 int main() 26 { 27 scanf("%d", &T); 28 while(T--) 29 { 30 scanf("%lld", &x); 31 ans = 0; 32 if (3 <= x && x <= 6){ 33 ans = -1; 34 output(); 35 continue; 36 } 37 for (int i = 3; i <= 6; i++) 38 for (int j = 3; j <= 6; j++) 39 if ((x-i) % j == 0){ 40 long long base = (x-i)/j; 41 if (base > i && base > j) ans++; 42 } 43 for (int i = 3; i <= 6; i++) 44 for (int j = 3; j <= 6; j++) 45 for (int k = 3; k <= 6; k++){ 46 long long a = i, b = j, c = -x+k; 47 long long delta = b * b - 4ll * a * c; 48 if (delta <= 0) continue; 49 long long srt = sqrt(double(delta)); 50 if (srt * srt == delta){ 51 long long tmp = -b + srt; 52 if (tmp % (a*2ll) == 0){ 53 long long base = tmp / (2ll*a); 54 if (base > i && base > j && base > k) ans++; 55 } 56 } 57 } 58 for (int base = 4; base <= 7000; base++){ 59 if (ok(x, base)) ans++; 60 } 61 output(); 62 } 63 return 0; 64 }
HDOJ 4938 Seeing People
题意:两类人,一类在x轴正半轴,一类在y轴正半轴,每个人有个位置和视距,第一类人往右看,第二类人往上看。两类人各有一种速度,然后每个人不同时间出发,第一类往上,第二类往右,然后问每个人能看见多少另一类不同的人。
分析:赛后做的。。网断了没法看题解。想了想其实不难。题解的做法没看懂。我大概是这么做的。因为变量比较多,所以我们把时间先后的因素给化解掉。假设目前考虑的是x轴上的人,那么y轴的人我们都固定为同一个高度,即相同y坐标,忘了当时是怎么考虑的,总之是选择了最大的那个坐标,可能精度误差小些?。然后对应出发时间也要改。然后推一下公式,然后就可以对分离出来的只关于y轴上点的坐标的一个变量排序,然后x轴上点看他们肯定是连续的,所以二分两端就可以了。另一种同理。复杂度o(nlgn)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 6 const double eps = 1e-6; 7 struct node{ 8 int s, t, p, w; 9 } p[int(1e5)+100]; 10 int cas = 0, T, n, v1, v2; 11 int ans[int(1e5)+100]; 12 double a[int(1e5)+100], b[int(1e5)+100]; 13 int main() 14 { 15 scanf("%d", &T); 16 while(T--) 17 { 18 scanf("%d %d %d", &n, &v1, &v2); 19 int max1 = 0, max2 = 0, cnt1 = 0, cnt2 = 0; 20 for (int i = 0; i < n; i++){ 21 scanf("%d %d %d %d", &p[i].s, &p[i].t, &p[i].p, &p[i].w); 22 if (p[i].s == 1){ 23 max1 = max(max1, p[i].p); 24 } 25 if (p[i].s == 2){ 26 max2 = max(max2, p[i].p); 27 } 28 } 29 printf("Case #%d:\n", ++cas); 30 for (int i = 0; i < n; i++){ 31 if (p[i].s == 1){ 32 a[cnt1++] = ((double)p[i].t + (double)(max1-p[i].p) / (double)v2) * (double)v1; 33 } 34 if (p[i].s == 2){ 35 b[cnt2++] = ((double)p[i].t + (double)(max2-p[i].p) / (double)v1) * (double)v2; 36 } 37 } 38 if (cnt1 == 0 || cnt2 == 0){ 39 for (int i = 0; i < n; i++) printf("0\n"); 40 continue; 41 } 42 sort(a, a+cnt1); 43 sort(b, b+cnt2); 44 //printf("%d %d\n", cnt1, cnt2); 45 for (int i = 0; i < n; i++){ 46 if (p[i].s == 1){ 47 double tmp = double(max2)/v1; 48 tmp = (tmp + p[i].t) * v2; 49 int ans1, ans2; 50 double key1 = tmp - p[i].p, key2 = tmp - p[i].p - p[i].w; 51 if (key1 > b[cnt2-1]) ans1 = cnt2-1; 52 else if (key1 < b[0]) ans1 = -1; 53 else{ 54 int l = 0, r = cnt2-1; 55 while(l <= r) 56 { 57 int mid = l + r >> 1; 58 if (b[mid] - key1 < eps){ 59 //if (b[mid] <= key1){ 60 ans1 = mid; 61 l = mid+1; 62 } 63 else r = mid-1; 64 } 65 } 66 if (key2 > b[cnt2-1]) ans2 = cnt2; 67 else if (key2 < b[0]) ans2 = 0; 68 else{ 69 int l = 0, r = cnt2-1; 70 while(l <= r) 71 { 72 int mid = l + r >> 1; 73 if (b[mid] - key2 > -eps){ 74 //if (b[mid] >= key2){ 75 ans2 = mid; 76 r = mid-1; 77 } 78 else l = mid+1; 79 } 80 } 81 ans[i] = ans1 - ans2 + 1; 82 } 83 if (p[i].s == 2){ 84 double tmp = double(max1)/v2; 85 tmp = (tmp + p[i].t) * v1; 86 int ans1, ans2; 87 double key1 = tmp - p[i].p, key2 = tmp - p[i].p - p[i].w; 88 89 if (key1 > a[cnt1-1]) ans1 = cnt1-1; 90 else if (key1 < a[0]) ans1 = -1; 91 else{ 92 int l = 0, r = cnt1-1; 93 while(l <= r) 94 { 95 int mid = l + r >> 1; 96 if (a[mid] - key1 < eps){ 97 //if (a[mid] <= key1){ 98 ans1 = mid; 99 l = mid+1; 100 } 101 else r = mid-1; 102 } 103 } 104 105 if (key2 > a[cnt1-1]) ans2 = cnt1; 106 else if (key2 < a[0]) ans2 = 0; 107 else{ 108 int l = 0, r = cnt1-1; 109 while(l <= r) 110 { 111 int mid = l + r >> 1; 112 if (a[mid] - key2 > -eps){ 113 //if (a[mid] >= key2){ 114 ans2 = mid; 115 r = mid-1; 116 } 117 else l = mid+1; 118 } 119 } 120 ans[i] = ans1 - ans2 + 1; 121 // printf("%d %d\n", ans1, ans2); 122 // printf("%.4f %.4f %.4f %d\n", key2, key1, a[0], cnt1); 123 } 124 } 125 for (int i = 0; i < n; i++) printf("%d\n", ans[i]); 126 } 127 return 0; 128 }
HDOJ 4939 Stupid Tower Defense
题意:塔防。n的长度的直线,每个位置可以种塔(为什么是种?),红塔攻击正在经过它的怪物,绿塔攻击已经经过它的怪物,蓝塔使经过它的怪物减速。每单位长度能种一个塔,问最大伤害。
分析:很容易得到一个三维的方程,就是dp[i][j]][k]表示前i个位置有j个蓝塔k个绿塔的最大伤害,当然超时啥的。然后考虑,显然红塔放最后不会比放前面差,就往贪心想了。但是通过计算发现绿塔和蓝塔哪个放前面或者以某种顺序交替放都不一定最优。突然又注意到红塔放最后的想法,于是就可以降掉dp的一维状态。dp[i][j]表示前i个位置蓝塔的个数为j,其余为绿塔的最大伤害。这样是2d0d的,o(n^2)。然后枚举从某个位置开始全放红塔,最后在其中选一个最大的即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstdlib> 7 #include<set> 8 #include<map> 9 #include<queue> 10 #include<ctime> 11 #include<string> 12 using namespace std; 13 14 int T, n, x, y, z, t; 15 long long f[1510][1510]; 16 int main() 17 { 18 int cas = 0; 19 scanf("%d", &T); 20 while(T--) 21 { 22 scanf("%d %d %d %d %d", &n, &x, &y, &z, &t); 23 memset(f, 0, sizeof(f)); 24 for (int i = 1; i <= n; i++) 25 for (int j = 0; j <= i; j++){ 26 long long tmp = f[i-1][j] + (long long)y * (i-1-j) * (t + j*z); 27 if (j > 0) tmp = max(tmp, f[i-1][j-1] + (long long)y * (i-j) * (t + (j-1)*z)); 28 f[i][j] = tmp; 29 if (i == j) f[i][j] = 0; 30 } 31 long long ans = 0; 32 for (int i = 0; i <= n; i++){ 33 for (int j = 0; j <= i; j ++){ 34 long long tmp = f[i][j] + (long long)(x + (i-j) * y) * (t + j*z) * (n - i); 35 if (tmp > ans) ans = tmp; 36 } 37 } 38 cas ++; 39 printf("Case #%d: %lld\n", cas, ans); 40 } 41 return 0; 42 }
HDOJ 4941 Magical Forest
题意&&分析:好像这题是维护一个行和列的映射,还有一个map记录原图中某位置的水果数。其实映射挺有意思的=。=
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<map> 5 using namespace std; 6 7 typedef pair<int, int> P; 8 int T, n, m, k, x, y, c, q; 9 map<P, int> p; 10 map<int, int> row, col; 11 12 int main() 13 { 14 scanf("%d", &T); 15 int cas = 0; 16 while(T--) 17 { 18 p.clear(); 19 row.clear(); col.clear(); 20 scanf("%d %d %d", &n, &m, &k); 21 for (int i = 0; i < k; i++){ 22 scanf("%d %d %d", &x, &y, &c); 23 row[x] = x; col[y] = y; 24 P tmp = make_pair(x, y); 25 p[tmp] = c; 26 } 27 printf("Case #%d:\n", ++cas); 28 scanf("%d", &q); 29 for (int i = 0; i < q; i++){ 30 scanf("%d %d %d", &c, &x, &y); 31 if (c == 1) swap(row[x], row[y]); 32 else if (c == 2) swap(col[x], col[y]); 33 else{ 34 P tmp = make_pair(row[x], col[y]); 35 printf("%d\n", p[tmp]); 36 } 37 } 38 } 39 return 0; 40 }