BestCoder Round #40

弱渣做不动CF了,弱渣只能水水BC了,于是就开始每周开心地BC了,顺便写个水水的题解~~

题A hdu 5224

题意:略

题解:枚举边长即可。

 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 int main() {
15 //  freopen("case.in", "r", stdin);
16   int T;
17   cin >> T;
18   while (T--) {
19     int n;
20     scanf("%d", &n);
21     int ans = 1 << 30;
22     for (int i = 1; i * i <= n; i++) {
23       if (n % i == 0) {
24         ans = min(ans, 2 * (i + n / i));
25       }
26     }
27     printf("%d\n", ans);
28   }
29   return 0;
30 }

代码君

题B hdu 5225

题意:略

题解:可以用递推算出每个大小为n的排列的逆序对总数,就是考虑每次增加n之后逆序对数增加多少,分别把n放在第一个位置……第n个位置。得到s[n];然后就是对于一个排列运用类似的方法,不断细化,想数位dp得到答案的过程一样。具体是这样,我也不知道怎么水出来的~~

 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 mod = 1e9 + 7, maxn = 1e2 + 10;
15 int p[maxn], vis[maxn], n;
16 ll s[maxn], f[maxn];
17
18 void init() {
19   f[1] = 1; s[1] = 0;
20   for (int i = 2; i < maxn; i++) {
21     f[i] = f[i - 1] * i % mod;
22     s[i] = (s[i - 1] * i % mod + f[i - 1] * i * (i - 1) / 2) % mod;
23   }
24 //  cout << s[5] << endl;
25 }
26
27 ll slove() {
28   ll ret = 0;
29   memset(vis, 0, sizeof vis);
30   ll big = 0;
31   for (int i = 1; i <= n; i++) {
32     for (int j = 1; j < p[i]; j++) if (!vis[j]) {
33       ll extra = 0;
34       for (int k = 1; k < j; k++) if (!vis[k]) extra++;
35       ret += ((big + extra) * f[n - i] + s[n - i]) % mod;
36       if (ret >= mod) ret -= mod;
37     }
38     for (int j = 1; j < p[i]; j++) if (!vis[j]) big++;
39     vis[p[i]] = 1;
40   }
41   return ret;
42 }
43
44 int main() {
45 //  freopen("case.in", "r", stdin);
46   init();
47   while (scanf("%d", &n) == 1) {
48     for (int i = 1; i <= n; i++) scanf("%d", p + i);
49     printf("%I64d\n", slove());
50   }
51   return 0;
52 }

代码君

题C hdu 5226

题意:略

题解:先说一下我的做法,对于一个组合数可以写成c(a, b) = c(a - 1, b - 1) + c(a - 1, b),所以上一行是下一行乘以2再减去最右端的(只加了一次),所以可以递推过去。然后就是这道题的一个坑点:不能直接求逆元。为什么呢?因为假设分子的p因子的个数更多,那么modp之后得到的就是0,所以这时候求逆元就不准了,究其原因就是因为gcd!=1,所以不能够求逆元,除去这种情况是可以的,因为p是素数。解决方法有两种:

1、lucas定理,因为是以p为一次划分,所以可以很有效地避免。

2、要求a!/ (b ! * (a - b)!),所以求出num[a]表示a!有多少个p,然后只要num[a] - num[b] - num[a - b] > 0就直接是0,其余就可以用逆元来处理。

最后官方并不需要我那样递推过去,而是用一个性质:C(x + 1,y)即为∑x C(i,y),具体可以联系杨辉三角来证。

 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 maxn = 2e5 + 10;
15 ll p;
16 ll f[maxn], c[maxn];
17
18 ll quick(ll a, ll b) {
19   ll ret = 1;
20   while (b > 0) {
21     if (b & 1) ret = ret * a % p;
22     a = a * a % p;
23     b = b / 2;
24   }
25   return ret;
26 }
27
28 void init() {
29   f[0] = 1;
30   for (int i = 1; i < maxn; i++) f[i] = f[i - 1] * i % p;
31   for (int i = 0; i < maxn; i++) c[i] = quick(f[i], p - 2);
32 }
33
34 ll C(int n, int m) {
35   if(n == 0 && m == 0) return 1;
36   if(n == 0) return 0;
37   if(n % p < m % p) return 0;
38   int x = n % p, y = m % p;
39   return f[x] * c[y] % p * c[x-y] % p * C(n / p, m / p);
40 }
41
42 ll slove(int x, int y) {
43   if (x < 0 || y < 0) return 0;
44   ll ret = 1  , s = 1;
45   for (int i = 1; i <= x; i++) {
46     s = (s * 2 % p - C(i - 1, y)) % p;
47     ret = (ret + s) % p;
48   }
49   return (ret + p) % p;
50 }
51
52 int main() {
53 //  freopen("case.in", "r", stdin);
54   int x1, x2, y1, y2;
55   while (scanf("%d%d%d%d%I64d", &x1, &y1, &x2, &y2, &p) != EOF) {
56     init();
57     ll ans1 = (slove(x2, y2) + slove(x1 - 1, y1 - 1)) % p;
58     ll ans2 = ((slove(x1 - 1, y2)) + slove(x2, y1 - 1)) % p;
59     ll ans = (ans1 - ans2) % p;
60     printf("%I64d\n", (ans + p) % p);
61   }
62   return 0;
63 }

代码君

题D hdu 5227

题意:给你四元对(t,a,b,k),满足下面条件就是合法的:

1、 1 <= a, b, k <= t

2、 gcd(a,b) >= k

然后给你一颗树,每个点表示一个四元对,随机选两个点,然后这路径上的点就是来玩游戏的点,玩游戏的方法就是每次选一个四元对,然后变成一个更小的合法四元对,然后最后不能操作者输,现在让你算出有多少种选法是必败的?

题解:很容易想到nim,每个四元对当做一堆石头,个数就是比它小的四元对个数,然后假设知道之后我们知道一条路径的异或值为0就是必败的,所以就转化成树分治的求异或值为0的路径数量,这个比较简单,所以本题就难在求比当前四元对小的合法的四元对的数量。

求这个东西太难了,要参考贾志鹏线性筛,以后再学吧,先套个公式吧 !!

  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 maxn = 1e4 + 10;
 15 int head[maxn], e = 0, n;
 16 ll phi[maxn], v[maxn], val[maxn];
 17
 18 struct Edge {
 19   int v, nx;
 20 } edges[maxn * 2];
 21
 22 ll get(int n, int m) {
 23   if (n > m) swap(n, m);
 24   ll ret = 0;
 25   for (int i = 1, j; i <= n; i = j + 1) {
 26     j = min(n / (n / i), m / (m / i));
 27     ret += 1ll * (phi[j] - phi[i - 1]) * (n / i) * (m / i);
 28   }
 29   return ret;
 30 }
 31
 32 void phi_table() {
 33   phi[1] = 1;
 34   for (int i = 2; i < maxn; i++) if (!phi[i])
 35     for (int j = i; j < maxn; j += i) {
 36       if (!phi[j]) phi[j] = j;
 37       phi[j] = phi[j] / i * (i - 1);
 38     }
 39   for (int i = 1; i < maxn; i++) phi[i] += phi[i - 1];
 40   for (int i = 1; i < maxn; i++) v[i] = v[i - 1] + get(i, i);
 41 }
 42
 43 void init() {
 44   e = 0;
 45   memset(head, -1, sizeof head);
 46 }
 47
 48 void add_edge(int u, int v) {
 49   edges[e] = (Edge){v, head[u]};
 50   head[u] = e++;
 51 }
 52
 53 int sz[maxn], vis[maxn];
 54
 55 void dfs_s(int u, int p) {
 56   sz[u] = 1;
 57   for (int i = head[u]; ~i; i = edges[i].nx) {
 58     int v = edges[i].v;
 59     if (v == p || vis[v]) continue;
 60     dfs_s(v, u);
 61     sz[u] += sz[v];
 62   }
 63 }
 64
 65 int dp[maxn];
 66
 67 void dfs_t(int& s, int u, int p, int cnt) {
 68   dp[u] = 0;
 69   for (int i = head[u]; ~i; i = edges[i].nx) {
 70     int v = edges[i].v;
 71     if (v == p || vis[v]) continue;
 72     dfs_t(s, v, u, cnt);
 73     dp[u] = max(dp[u], sz[v]);
 74   }
 75   dp[u] = max(dp[u ], cnt - sz[u]);
 76   if (s == -1 || dp[u] < dp[s]) s = u;
 77 }
 78
 79 ll c1[maxn]; int c;
 80
 81 void dfs_c(int u, int p, ll d) {
 82   c1[c++] = d;
 83   for (int i = head[u]; ~i; i = edges[i].nx) {
 84     int v = edges[i].v;
 85     if (v == p || vis[v]) continue;
 86     dfs_c(v, u, d ^ val[v]);
 87   }
 88 }
 89
 90 map<ll,int>::iterator it;
 91
 92 ll slove(int s) {
 93   dfs_s(s, -1);
 94   int cnt = sz[s], t = s;
 95   s = -1;
 96   dfs_t(s, t, -1, cnt);
 97   vis[s] = 1;
 98   ll ret = 0;
 99   if (!val[s]) ret++;
100   map<ll,int> mp;
101   for (int i = head[s]; ~i; i = edges[i].nx) {
102     int v = edges[i].v;
103     if (vis[v]) continue;
104     c = 0;
105     dfs_c(v, s, val[v]);
106     for (int j = 0; j < c; j++) {
107       if ((c1[j] ^ val[s]) == 0) ret += 2;
108       it = mp.find(c1[j] ^ val[s]);
109       if (it != mp.end()) ret += (*it).yy * 2;
110     }
111     for (int j = 0; j < c; j++) mp[c1[j]]++;
112   }
113   for (int i = head[s]; ~i; i = edges[i].nx) {
114     int v = edges[i].v;
115     if (vis[v]) continue;
116     ret += slove(v);
117   }
118   return ret;
119 }
120
121 ll gcd(ll a, ll b) {
122   if (!b) return a;
123   return gcd(b, a % b);
124 }
125
126 int main() {
127 //  freopen("case.in", "r", stdin);
128   phi_table();
129   while (scanf("%d", &n) == 1) {
130     init();
131     for (int i = 1; i < n; i++) {
132       int u, v;
133       scanf("%d%d", &u, &v);
134       add_edge(u, v); add_edge(v, u);
135     }
136     for (int i = 1; i <= n; i++) {
137       int a, b, c, d;
138       scanf("%d%d%d%d", &a, &b, &c, &d);
139       val[i] = v[a - 1] + d - 1;
140       val[i] += get(b - 1, a);
141       val[i] += get(b, c - 1) - get(b - 1, c - 1);
142     }
143     memset(vis, 0, sizeof vis);
144     ll a = 1ll * n * n - slove(1), b = 1ll * n * n;
145     if (!a) puts("0/1");
146     else {
147       ll d = gcd(a, b);
148       printf("%I64d/%I64d\n", a / d, b / d);
149     }
150   }
151   return 0;
152 }

代码君

时间: 2024-10-26 07:58:26

BestCoder Round #40的相关文章

HDU 5224 Tom and paper(BestCoder Round #40)

题目链接:Tom and paper 题面: Tom and paper Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 679    Accepted Submission(s): 432 Problem Description There is a piece of paper in front of Tom, its length

BestCoder Round #40 解题报告

这场是第一场没有米的BC... 大概也是想震一震那些一听说没米了就不打BC的人吧 这次的题目质量比以往高了许多 (然而我并没有打这一场BC 但是今天下午到现在做的过程中真的学到了不少知识呢 A题略水... 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cmath> 5 int T,n; 6 int main(){ 7 scanf("%d",&am

BestCoder Round #40 1001——精度——Tom and paper

Problem Description There is a piece of paper in front of Tom, its length and width are integer. Tom knows the area of this paper, he wants to know the minimum perimeter of this paper. Input In the first line, there is an integer T indicates the numb

HDU5226 Tom and matrix(BestCoder Round #40)

Tom and matrix Accepts: 29 Submissions: 225 Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 Tom放学回家的路上,看到天空中出现一个矩阵.Tom发现,如果矩阵的行.列从0开始标号,第i行第j列的数记为ai,j,那么ai,j=Cji 如果i < j,那么ai,j=0 Tom突发奇想,想求一个矩形范围内所有数的和.Tom急着回家,当然

HDU5224 Tom and paper(BestCoder Round #40)

Tom and paper Accepts: 464 Submissions: 955 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 Tom面前有一张纸,它的长和宽都是整数.Tom知道这张纸的面积n,他想知道这张纸的周长最小是多少. 输入描述 有多组数据.第一行一个正整数T,表示数据组数.接下来T行,每行一个正整数n,表示纸的面积. T≤10,n≤109 输出描述 对于每

hdu5225 Tom and permutation(BestCoder Round #40)

Tom and permutation Accepts: 120 Submissions: 422 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 Tom学会了通过写程序求出一个1-n的排列的逆序对数,但他的老师给了他一个难题: 给出一个1-n的排列,求所有字典序比它小的1-n的排列的逆序对数之和. Tom一时不知道该怎么做,所以他来找你帮他解决这个问题. 因为数可能很大,

BestCoder Round #40 A B C

A,水题,直接枚举到sqrt B,每次对于每一位枚举,如果小于当前位,那么答案可以计算出来,增加得答案为:设3个部分,前完全一样的部分a,中间新选的一个b,后面的全排列c,这样就把每部分和每两部分能够组成的逆序对个数计算出来,由于n只有100,里面在去枚举也是没问题的,主要是后面全排列c的逆序对数,这个可以利用dp处理出来,dp[i] = dp[i - 1] * i + i! * sum(i - 1),sum(i)表示1到i的和. C:推公式,C(n, m) = C(n - 1, m - 1)

BestCoder Round #16

BestCoder Round #16 题目链接 这场挫掉了,3挂2,都是很sb的错误 23333 QAQ A:每个数字,左边个数乘上右边个数,就是可以组成的区间个数,然后乘的过程注意取模不然会爆掉 B:dp,dp[i][2]记录下第一长的LIS,和第二长的LIS,哎,转移的时候一个地方写挫掉了导致悲剧啊QAQ C:首先如果知道Nim游戏的,就很容易转化问题为,一些数字是否能选几个能否异或和为0,那么就是每个数字拆成40位,然后每一位异或和为0,这样就可以构造出40个方程,然后高斯消元求解,如果

BestCoder Round #4 前两题 hdu 4931 4932

第一题太水了.. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int a[6]; 7 int main(){ 8 int cas; 9 scanf( "%d", &cas ); 10 while( cas-- ){ 11 for( int i = 0; i <