BestCoder Round #85

5/5

好久没写博客了,难得有空写个题解,难得有空补不动~~

 

题A hdu5776 sum

题意:略

题解:dp[x]表示前缀modm的余数有没有出现,如果同一个结果出现两次,那么就说明中间的一段是可以整除m的,当然不要忘了本身前缀就能够整除。

 

 1 /*zhen hao*/
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <queue>
 6 #include <vector>
 7 #include <string>
 8 #include <stack>
 9 #include <set>
10 #include <map>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14 
15 #define lson l, m, rt*2
16 #define rson m + 1, r, rt*2+1
17 #define xx first
18 #define yy second
19 
20 typedef pair<int,int> pii;
21 typedef long long ll;
22 typedef unsigned long long ull;
23 
24 const int N = 5e3 + 10;
25 int dp[N];
26 
27 int main() {
28 //    freopen("case.in", "r", stdin);
29 
30     int T;
31     cin >> T;
32     while (T--) {
33         memset(dp, 0, sizeof dp);
34         int n, m, now = 0, ok = 0;
35         scanf("%d%d", &n, &m);
36         for (int i = 0; i < n; i++) {
37             int x;
38             scanf("%d", &x);
39             now = (now + x) % m;
40             if (now == 0 || dp[now]) ok = 1;
41             dp[now] = 1;
42         }
43         if (ok) puts("YES"); else puts("NO");
44     }
45 
46 }
代码君

 

题B hdu5777 domino

题意:略

题解:仔细观察发现贪心可解,sort一下即可。

 

 1 /*zhen hao*/
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <queue>
 6 #include <vector>
 7 #include <string>
 8 #include <stack>
 9 #include <set>
10 #include <map>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14 
15 #define lson l, m, rt*2
16 #define rson m + 1, r, rt*2+1
17 #define xx first
18 #define yy second
19 
20 typedef pair<int,int> pii;
21 typedef long long ll;
22 typedef unsigned long long ull;
23 
24 const int N = 1e5 + 10;
25 int d[N];
26 
27 int main() {
28 //    freopen("case.in", "r", stdin);
29 
30     int T;
31     cin >> T;
32     while (T--) {
33         int n, k;
34         scanf("%d%d", &n, &k);
35         for (int i = 0; i < n - 1; i++) {
36             scanf("%d", d + i);
37         }
38         sort(d, d + n - 1, greater<int>());
39         ll sum = 0;
40         for (int i = k - 1; i < n - 1; i++) {
41             sum = sum + d[i];
42         }
43         printf("%I64d\n", sum + n);
44     }
45 
46 }
代码君

 

题C hdu5778 abs

题意:略

题解:质因子都是2说明这个数一定是平方数,然后对于x,我们先把它去个根的sx,然后我们枚举距离这个sx最近的距离d,然后判断d的质因子是不是都是一个。还有一个问题,我们取得这个sx可能sx+1更优,所以要先判断一下哪个距离x更近。

 

 1 /*zhen hao*/
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <queue>
 6 #include <vector>
 7 #include <string>
 8 #include <stack>
 9 #include <set>
10 #include <map>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14 
15 #define lson l, m, rt*2
16 #define rson m + 1, r, rt*2+1
17 #define xx first
18 #define yy second
19 
20 typedef pair<int,int> pii;
21 typedef long long ll;
22 typedef unsigned long long ull;
23 
24 const int N = 1e5 + 10;
25 bool vis[N];
26 vector<int> p;
27 
28 void init() {
29     for (int i = 2; i < N; i++) if (!vis[i])
30         for (int j = i + i; j < N; j += i) vis[j] = 1;
31     for (int i = 2; i < N; i++) if (!vis[i]) p.push_back(i);
32 }
33 
34 bool check(ll n) {
35     if (n < 2) return false;
36     int m = (int)sqrt(n + 0.5);
37     for (int i = 0; i < (int)p.size() && p[i] <= m; i++) if (n % p[i] == 0) {
38         int c = 0;
39         while (n % p[i] == 0) {
40             n /= p[i];
41             c++;
42         }
43         if (c > 1) return false;
44     }
45     return true;
46 }
47 
48 int main() {
49 //    freopen("case.in", "r", stdin);
50 
51     init();
52     int T;
53     cin >> T;
54     while (T--) {
55         ll x;
56         scanf("%I64d", &x);
57         ll sx = (ll)sqrt(x + 0.5);
58         if (abs(sx * sx - x) > abs((sx + 1) * (sx + 1) - x)) ++sx;
59         int d = 0;
60         while (true) {
61             if (check(sx + d)) break;
62             if (check(sx - d)) break;
63             d++;
64         }
65         ll res = 1e18;
66         if (check(sx + d)) res = min(res, abs(x - (sx + d) * (sx + d)));
67         if (check(sx - d)) res = min(res, abs(x - (sx - d) * (sx - d)));
68         cout << res << endl;
69     }
70 
71 }
代码君

 

题D 5779 Tower Defence

题意:略

题解:太弱了,第一眼看不到题解的状态转移,实际上题解的状态转移描述得已经够专业了。但是我是结合代码才看得懂(/▽╲)!!这里详细地解释一下怎么转移的吧,毕竟都把代码看懂了。

 

题目说最短路不是k,很容易由反证法得到这个最短路是小于k的。

先定义一个状态数组,f(i,j,k)表示与1连接的那个连通块(包括1)的size,当前的最短路是j,得到这个最短路的点数是k。

我们发现如果想要最短路的长度加一,那么必须是从非连通块里面的点连到这k个点的其中x个(1 <= x <= k),所以我们要枚举接下来的连通块以外的新点的个数x,目的是更新状态f(i+x,j+1,x)。

转移:(假设上一层是k个点,下一层是x个点)

(1)对于第二层的每个点x,从第一层的k个点里面人选1到k个连边,方法数是2 ^ k - 1。

(2)对于第二层的每个点x自己互相连边,方案数是2 ^ (x * (x - 1) / 2),因为共有这么条边,可以连也可以不连

(3)这个最难想,因为我们增加了x个点,那么原来图中有多少个点是可以换位置的呢?答案就是非1和非最短路为j的点,所以由i - k - 1个点里面选x作为最短路为j+1的点。

 

这三步我们得到了f(i,j,k)。

给定n和k怎么得到答案呢?枚举与1连通的点,然后剩余的点可以乱排,同样要考虑排列组合。

 

 1 /*zhen hao*/
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 
 5 #define lson l, m, rt*2
 6 #define rson m + 1, r, rt*2+1
 7 #define xx first
 8 #define yy second
 9 
10 typedef pair<int,int> pii;
11 typedef long long ll;
12 typedef unsigned long long ull;
13 
14 const int N = 61, mod = 1e9 + 7;
15 ll f[N][N][N], C[N][N], p2[N * N], p2_1[N];
16 
17 void add(ll& a, ll b) {
18     a += b;
19     if (a >= mod) a -= mod;
20 }
21 
22 void init() {
23     for (int i = 0; i < N; i++) {
24         C[i][0] = 1;
25         for (int j = 1; j <= i; j++)
26             add(C[i][j], (C[i - 1][j] + C[i - 1][j - 1]) % mod);
27     }
28 //    cout << C[5][3] << endl;
29     p2[0] = p2_1[0] = 1;
30     for (int i = 1; i < N * N; i++) p2[i] = p2[i - 1] * 2 % mod;
31     for (int i = 1; i < N; i++) p2_1[i] = (p2[i] + mod - 1) % mod;
32 //    cout << p2[5] << ' ' << p2_1[5] << endl;
33     f[1][0][1] = 1;
34     for (int i = 1; i < N; i++)
35         for (int j = 0; j < i; j++)
36             for (int k = 1; k <= i; k++) if (f[i][j][k]) {
37                 ll tmp = f[i][j][k];
38                 for (int l = 1; l + i < N; l++) {
39                     tmp = tmp * p2_1[k] % mod;
40                     ll val = tmp;
41                     val = val * p2[l * (l - 1) / 2] % mod;
42                     val = val * C[i + l - 1][l] % mod;
43                     add(f[i + l][j + 1][l], val);
44                 }
45             }
46 }
47 
48 ll get_ans(int n, int k) {
49     ll ans = 0;
50     for (int i = 1; i <= n; i++)
51         for (int j = 0; j < k; j++)
52             for (int l = 1; l <= i; l++) if (f[i][j][l]) {
53                 ll tmp = f[i][j][l];
54                 tmp = tmp * C[n - 1][n - i] % mod;
55                 tmp = tmp * p2[(n - i) * (n - i - 1) / 2] % mod;
56                 add(ans, tmp);
57             }
58     return ans;
59 }
60 
61 int main() {
62 //    freopen("case.in", "r", stdin);
63 
64     init();
65     int T;
66     cin >> T;
67     while (T--) {
68         int n, k;
69         cin >> n >> k;
70         cout << get_ans(n, k) << '\n';
71     }
72 
73     return 0;
74 }
代码君

 

题E hdu5780 gcd

题意:略

题解:实际上官方题解已经写得很详细了,我再复述有点多余(/▽╲)改天有空补上这个公式证明吧,希望我不会忘记。

 

 1 /*zhen hao*/
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 
 5 #define lson l, m, rt*2
 6 #define rson m + 1, r, rt*2+1
 7 #define xx first
 8 #define yy second
 9 
10 typedef pair<int,int> pii;
11 typedef long long ll;
12 typedef unsigned long long ull;
13 
14 const int N = 1e6, mod = 1e9 + 7;
15 int phi[N + 10];
16 ll s[N + 10];
17 
18 void phi_table() {
19     phi[1] = 1;
20     for (int i = 2; i <= N; i++) if (!phi[i])
21         for (int j = i; j <= N; j += i) {
22             if (!phi[j]) phi[j] = j;
23             phi[j] = phi[j] / i * (i - 1);
24         }
25     for (int i = 1; i <= N; i++)
26         s[i] = (s[i - 1] + phi[i]) % mod;
27 }
28 
29 ll quick(ll a, ll b, ll c) {
30     ll ret = 1;
31     while (b > 0) {
32         if (b & 1) ret = ret * a % c;
33         b = b / 2;
34         a = a * a % c;
35     }
36     return ret;
37 }
38 
39 ll get_ans(int x, int n) {
40     if (x == 1) return 0ll;
41     ll ret = 0;
42     ll inv = quick(x - 1, mod - 2, mod);
43     for (int i = 1, j; i <= n; i = j + 1) {
44         j = n / (n / i);
45         ll sd = 2ll * s[n / i] - 1;
46         ll a0 = quick(x, i, mod), qn = quick(x, j - i + 1, mod) + mod - 1;
47         ll tmp = a0 * qn % mod;
48         tmp = tmp * inv % mod;
49         tmp = (tmp + mod - (j - i + 1)) % mod;
50         tmp = sd * tmp % mod;
51         ret += tmp;
52         if (ret >= mod) ret -= mod;
53     }
54     return ret;
55 }
56 
57 int main() {
58 //    freopen("case.in", "r", stdin);
59 
60     phi_table();
61     int T;
62     cin >> T;
63     while (T--) {
64         int x, n;
65         scanf("%d%d", &x, &n);
66         cout << get_ans(x, n) << endl;
67     }
68 
69     return 0;
70 }
代码君

 

转载于:https://www.cnblogs.com/zhenhao1/p/5724177.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值