编程之美2015资格赛 解题报告

题目链接:http://hihocoder.com/contest/msbop2015qual/problems

 

A. 2月29日

首先为了方便处理可以分类一下把问题转化成第a年到第b年的闰年数量。

然后如果要求fun(x)=1~x年中闰年的数量,容斥一下就是 (1~x中4的倍数) - (1~x中100的倍数) + (1~x中400的倍数)

答案为fun(b) - fun(a-1)。

 

代码(1ms):

 1 #include <cstdio>

 2 #include <algorithm>

 3 #include <cstring>

 4 #include <iostream>

 5 using namespace std;

 6 

 7 string month[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November" , "December"};

 8 int T, n;

 9 

10 int get_month(string s) {

11     return find(month, month + 12, s) - month + 1;

12 }

13 

14 int calc(int y) {

15     return y / 4 - y / 100 + y / 400;

16 }

17 

18 char str[15];

19 int yy, dd, mm;

20 

21 int main() {

22     scanf("%d", &T);

23     for(int t = 1; t <= T; ++t) {

24         scanf("%s %d, %d", str, &dd, &yy);

25         mm = get_month(str);

26         int a = calc(yy + (mm > 2) - 1);

27 

28         scanf("%s %d, %d", str, &dd, &yy);

29         mm = get_month(str);

30         int b = calc(yy - (mm < 2 || (mm == 2 && dd < 29)));

31         printf("Case #%d: %d\n", t, b - a);

32     }

33 }
View Code

 

B. 回文字符序列

此题为DP,用dp[i][j]表示s[i..j]中的回文子序列数量。

那么,不考虑s[i] = s[j]的回文串,dp[i][j] = dp[i+1][j] + dp[i][j - 1] - dp[i+1][j-1](容斥,怎么又是容斥……)

那么考虑包含s[i] = s[j]的回文串,dp[i][j] = dp[i + 1][j - 1] + 1(1表示回文串s[i]s[j])

其中初始化为s[i][i] = 1。

记得取模。答案为dp[1][n]。

 

代码(126ms):

 1 #include <cstdio>

 2 #include <algorithm>

 3 #include <iostream>

 4 #include <cstring>

 5 using namespace std;

 6 

 7 const int MAXN = 1010;

 8 const int MOD = 100007;

 9 

10 char s[MAXN];

11 int dp[MAXN][MAXN];

12 int T, n;

13 

14 int solve() {

15     for(int i = 0; i < n; ++i) dp[i][i] = 1;

16     for(int step = 1; step < n; ++step) {

17         for(int l = 0; l + step < n; ++l) {

18             int r = l + step;

19             dp[l][r] = (dp[l + 1][r] + dp[l][r - 1] - dp[l + 1][r - 1] + MOD) % MOD;

20             if(s[l] == s[r]) {

21                 dp[l][r] = (dp[l][r] + dp[l + 1][r - 1] + 1) % MOD;

22             }

23         }

24     }

25     return dp[0][n - 1];

26 }

27 

28 int main() {

29     scanf("%d", &T);

30     for(int t = 1; t <= T; ++t) {

31         scanf("%s", s);

32         n = strlen(s);

33         printf("Case #%d: %d\n", t, solve());

34     }

35 }
View Code

 

C. 基站选址

这题我就随手写了个模拟退火……

其实这题的用户坐标的x、y是无关的,在不考虑基站的情况下,质心P(sum{x}/A, sum{y}/B)是最好的(求导可得)。

然而,P移动一个坐标,sum{(A-P)·(A-P)}的偏移≥1,而与基站的哈曼顿距离偏移≤1。

那么只要枚举P周围的9个点就行了,复杂度O(A+B)。不放心的可以枚举25个点。

 

代码(95ms):

 1 #include <cstdio>

 2 #include <cstring>

 3 #include <algorithm>

 4 #include <iostream>

 5 #include <cmath>

 6 #include <cassert>

 7 using namespace std;

 8 typedef long long LL;

 9 

10 const int MAXN = 1010;

11 

12 int ax[MAXN], ay[MAXN], bx[MAXN], by[MAXN];

13 int a, b, n, m, T;

14 int now_x, now_y;

15 

16 LL sqr(int x, int y) {

17     return LL(x) * x + LL(y) * y;

18 }

19 

20 LL calc(int x, int y) {

21     LL res = 0x3f3f3f3f;

22     for(int i = 0; i < b; ++i)

23         res = min(res, LL(abs(x - bx[i]) + abs(y - by[i])));

24     for(int i = 0; i < a; ++i)

25         res += sqr(x - ax[i], y - ay[i]);

26     return res;

27 }

28 

29 LL get_ans(int x, int y) {

30     LL res = ~(1LL << 63);

31     for(int i = -1; i <= 1; ++i)

32         for(int j = -1; j <= 1; ++j) res = min(res, calc(x + i, y + j));

33     return res;

34 }

35 

36 LL solve() {

37     static int fx[] = {1, 0, -1, 0};

38     static int fy[] = {0, 1, 0, -1};

39 

40     int x = (n + 1) / 2, y = (n + 1) / 2;

41     double step = max(n, m) / 2, v = 0.95;

42     LL res = calc(x, y);

43 

44     while(step > 1e-4) {

45         int p = int(ceil(step));

46         for(int f = 0; f < 4; ++f) {

47             int new_x = x + p * fx[f], new_y = y + p * fy[f];

48             LL tmp = calc(new_x, new_y);

49             if(tmp < res) {

50                 res = tmp;

51                 x = new_x, y = new_y;

52             }

53         }

54         step *= v;

55     }

56     //cout<<res<<" # debug #"<<endl; assert(get_ans(x, y) == res);

57     return get_ans(x, y);

58 }

59 

60 LL test() {

61     LL res = ~(1LL << 63);

62     for(int i = 1; i <= n; ++i)

63         for(int j = 1; j <= m; ++j) res = min(res, calc(i, j));

64     return res;

65 }

66 

67 int main() {

68     //freopen("input.txt", "r", stdin);

69     scanf("%d", &T);

70     for(int t = 1; t <= T; ++t) {

71         scanf("%d%d%d%d", &n, &m, &a, &b);

72         for(int i = 0; i < a; ++i) scanf("%d%d", &ax[i], &ay[i]);

73         for(int i = 0; i < b; ++i) scanf("%d%d", &bx[i], &by[i]);

74         //cout<<calc(2, 2)<<endl;

75         cout<<"Case #"<<t<<": "<<solve()<<endl;

76         //cout<<"#debug "<<test()<<endl;

77     }

78 }
View Code

 

你可能感兴趣的:(编程之美)