zoukankan      html  css  js  c++  java
  • BestCoder Round #40

    4/4

    弱渣做不动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
    ", 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
    ", 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
    ", (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
    ", a / d, b / d);
    149     }
    150   }
    151   return 0;
    152 }
    代码君

     

  • 相关阅读:
    2013 Multi-University Training Contest 6 部分解题报告
    2013 Multi-University Training Contest 5 部分解题报告
    Codeforces Round #195 (Div. 2) 解题报告
    (转) tarjan算法
    重装SQLServer2008
    关于此博客园及其美化
    矩阵乘法
    CSP-S2019部分题解
    二维偏序
    [BOI2003]团伙
  • 原文地址:https://www.cnblogs.com/zhenhao1/p/5510349.html
Copyright © 2011-2022 走看看