【HNOI2013】題解 bzoj3139~bzoj3144

比賽php

  題目:  http://www.lydsy.com/JudgeOnline/problem.php?id=3139c++

  題解:
數組

    3$\le$N$\le$10,比較明顯是一個搜索題,一開始我是直接搜了,沒有記憶化,若是先枚舉每一隊能夠的勝負平,加上合法性判斷,再進行枚舉,那麼是能夠拿到70分的,這裏有一個重要的剪枝,在枚舉了每一隊的狀況後必定要判斷勝場+負場是否相等,這裏有20分。。網絡

      如下正解:ide

    在爆搜的時候咱們每一隊每一隊去枚舉,咱們嘗試着記憶化。優化

    首先咱們發現,對於一組數據,得分序列(讀入序列)的順序和答案是無關的,那麼咱們記憶當還有x個隊沒有處理時,每一隊的剩餘得分爲$a_{n - x + 1}$,$a_{n - x + 2}$,......,$a_{n}$ 這個狀態對答案的貢獻,經過對這個數組的排序,咱們能夠大量去重,甚至不須要加太多的優化均可以AC。spa

 1 #include <bits/stdc++.h>
 2 #define rep(i, a, b) for (int i = a; i <= b; i++)
 3 #define drep(i, a, b) for (int i = a; i >= b; i--)
 4 #define REP(i, a, b) for (int i = a; i < b; i++)
 5 #define mp make_pair
 6 #define pb push_back
 7 #define clr(x) memset(x, 0, sizeof(x))
 8 #define xx first
 9 #define yy second
10 using namespace std;
11 typedef long long i64;
12 typedef pair<int, int> pii;
13 const int inf = 0x3f3f3f3f;
14 const i64 INF = 0x3f3f3f3f3f3f3f3fll;
15 template <typename T> void Max(T &a, T b) { if (a < b) a = b; }
16 template <typename T> void Min(T &a, T b) { if (a > b) a = b; }
17 //***************************************************************
18 
19 int n;
20 struct Conditions {
21     int a[11];
22     inline long long hash() {
23         long long ret = 0;
24         rep(i, 0, n) ret = ret * 28 + a[i];
25         return ret;
26     }
27     inline void Sort() { sort(a + n - a[0] + 1, a + 1 + n); }
28 } start, bound;
29 map <i64, i64> M;
30 const int mod = 1e9 + 8;
31 long long dfs(int step, Conditions now) {
32     if (now.a[0] == 1) return M[now.hash()];
33     if (now.a[n - now.a[0] + 1] > 3 * (n + 1 - step)) return -1;
34     if (step > n) {
35         now.a[0]--;
36         now.Sort();
37         if (M[now.hash()]) return M[now.hash()];
38         return M[now.hash()] = dfs(n - now.a[0] + 2, now);
39     }
40     long long res = 0, tmp;
41     int idx = n - now.a[0] + 1;
42     if (now.a[idx] >= 3) {
43         now.a[idx] -= 3;
44         tmp = dfs(step + 1, now);
45         if (tmp != -1) (res += tmp) %= mod;
46         now.a[idx] += 3;
47     }
48     if (now.a[idx] >= 1 && now.a[step] >= 1) {
49         now.a[idx] -= 1, now.a[step] -= 1;
50         tmp = dfs(step + 1, now);
51         if (tmp != -1) (res += tmp) %= mod;
52         now.a[idx] += 1, now.a[step] += 1;
53     }
54     if (now.a[step] >= 3) {
55         now.a[step] -= 3;
56         tmp = dfs(step + 1, now);
57         if (tmp != -1) (res += tmp) %= mod;
58         now.a[idx] += 1;
59         now.a[step] += 3;
60     }
61     res = res ? res : -1;
62     return res;
63 }
64 int main() {
65     scanf("%d", &n);
66     start.a[0] = n;
67     rep(i, 1, n) scanf("%d", &start.a[i]);
68     start.Sort();
69     bound.a[0] = 1, bound.a[n] = 0; M[bound.hash()] = 1;
70     printf("%lld\n", dfs(2, start));
71     return 0;
72 }
View Code

 

 

 

消毒code

  題目: http://www.lydsy.com/JudgeOnline/problem.php?id=3140
blog

  題解:排序

    a * b * c$\le$5000,因此min(a, b, c)$\le$18。

    首先若是用長度爲p * q * r的立方題來框住這些點,咱們能夠把它變成用 1 * p * q 或者 1 * q * r 或者 p * 1 * r的立方體來覆蓋,答案不會更差。

    那麼咱們能夠用來填充的無非是上面3種的立方體來覆蓋,那麼咱們能夠枚舉最小的那一維,剩下的用二分圖最小點覆蓋。

    咱們把最小的那一維旋轉到x軸上,咱們二進制枚舉這一維 複雜度爲$2^{18}$,剩下的咱們只能用 p * q * 1 或者 p * 1 * r 來覆蓋剩下的點,那麼咱們把不能用x軸(1 * q * r)覆蓋的點分別映射到y軸,z軸上去,以後二分圖最小點覆蓋,也就是最大匹配,記得matrix67大神證實過König定理 http://www.matrix67.com/blog/archives/116?replytocom=4432

 1 #include <bits/stdc++.h>
 2 #define rep(i, a, b) for (int i = a; i <= b; i++)
 3 #define drep(i, a, b) for (int i = a; i >= b; i--)
 4 #define REP(i, a, b) for (int i = a; i < b; i++)
 5 #define pb push_back
 6 #define mp make_pair
 7 #define clr(x) memset(x, 0, sizeof(x))
 8 #define xx first
 9 #define yy second
10 using namespace std;
11 typedef long long i64;
12 typedef pair<int, int> pii;
13 const int inf = 0x3f3f3f3f;
14 const i64 INF = 0x3f3f3f3f3f3f3f3f;
15 template <typename T> void Max(T &a, T b) { if (a < b) a = b; }
16 template <typename T> void Min(T &a, T b) { if (a > b) a = b; }
17 //********************************************************************
18 
19 const int maxn = 5005;
20 
21 struct point {
22     int x, y, z; point() {}
23     point(int _x, int _y, int _z) :
24         x(_x), y(_y), z(_z) {}
25 } one[maxn];
26 int cnt_one;
27 struct Ed {
28     int u, v, nx; Ed() {}
29     Ed(int _u, int _v, int _nx) :
30         u(_u), v(_v), nx(_nx) {}
31 } E[maxn];
32 int G[maxn], edtot;
33 void addedge(int u, int v) {
34     E[++edtot] = Ed(u, v, G[u]);
35     G[u] = edtot;
36 }
37 int A, B, C;
38 
39 bool t[maxn], used[maxn]; int belong[maxn];
40 bool dfs(int x) {
41     for (int i = G[x]; i; i = E[i].nx) {
42         if (used[E[i].v]) continue;
43         used[E[i].v] = 1;
44         if (!belong[E[i].v] || dfs(belong[E[i].v])) {
45             belong[E[i].v] = x;
46             return true;
47         }
48     }
49     return false;
50 }
51 int ans;
52 void solve() {
53     static int hsh[maxn]; int hsh_cnt(0);
54     rep(i, 1, cnt_one) hsh[hsh_cnt++] = one[i].x;
55     sort(hsh, hsh + hsh_cnt); hsh_cnt = unique(hsh, hsh + hsh_cnt) - hsh;
56     REP(s, 0, 1 << hsh_cnt) {
57         rep(i, 1, A) t[i] = 0;
58         int tmp(0);
59         REP(i, 0, hsh_cnt) if (s >> i & 1) t[hsh[i]] = 1, tmp++;
60         edtot = 0; rep(i, 1, B) G[i] = 0;
61         rep(i, 1, cnt_one) if (!t[one[i].x]) addedge(one[i].y, one[i].z);
62         rep(i, 1, C) belong[i] = 0;
63         rep(i, 1, B) {
64             rep(j, 1, C) used[j] = 0;
65             if (dfs(i)) tmp++;
66             if (tmp > ans) break;
67         }
68         Min(ans, tmp);
69     }
70 }
71 
72 int main() {
73     int T; scanf("%d", &T);
74     while (T--) {
75         scanf("%d%d%d", &A, &B, &C);
76         cnt_one = 0;
77         rep(i, 1, A) rep(j, 1, B) rep(k, 1, C) {
78             int id; scanf("%d", &id);
79             if (id == 1) one[++cnt_one] = point(i, j, k);
80         }
81         if (B > A) { swap(A, B); rep(i, 1, cnt_one) swap(one[i].x, one[i].y); }
82         if (C > A) { swap(A, C); rep(i, 1, cnt_one) swap(one[i].x, one[i].z); }
83         ans = A;
84         solve();
85         printf("%d\n", ans);
86     }
87 }
View Code

 

 

旅行

  題目: http://www.lydsy.com/JudgeOnline/problem.php?id=3141

  題解:

    

 

數列

  題目: http://www.lydsy.com/JudgeOnline/problem.php?id=3142

  題解:

    原數列$\underbrace{ a_{1},a_{2},a_{3}......a_{k} }_{k}$

    構造數列$b_{i}=a_{i}-a_{i-1}$

    那麼咱們獲得$\underbrace{ b_{1},b_{2},b_{3}......a_{k-1} }_{k-1}$

    咱們考慮每一個不一樣數列的不一樣貢獻。

    貢獻爲:$n-b_{1}-b_{2}-b_{3}-b_{4}-b_{k-1}$

    由於$m*(k-1)>n$因此每個數列都有如上貢獻,共有$m^{k-1}$種狀況

    那麼求和

    n的貢獻是$n*m^{k-1}$

    對於剩下的每一項,任取一項,在這一項取1時,共有$m^{k-2}$個數列,取2時,共有$m^{k-2}$個數列......

    那麼對於$b_{k}$對答案的貢獻是$(\sum_{i=1}^{m})*m^{k-2}$

    因此總答案爲$n*m^{k-1}+(k-1)*(\sum_{i=1}^{m})*m^{k-2}$

 1 #include <bits/stdc++.h>
 2 #define rep(i, a, b) for (int i = a; i <= b; i++)
 3 #define drep(i, a, b) for (int i = a; i >= b; i++)
 4 #define REP(i, a, b) for (int i = a; i < b; i++)
 5 #define mp make_pair
 6 #define pb push_back
 7 #define xx first
 8 #define yy second
 9 using namespace std;
10 typedef long long ll;
11 typedef pair<int, int> pii;
12 const int inf = 0x3f3f3f3f;
13 const ll INT = 0x3f3f3f3f3f3f3f3fll;
14 template <typename T> void Max(T &a, T b) { if (a < b) a = b; }
15 template <typename T> void Min(T &a, T b) { if (a > b) a = b; }
16 //******************************************************************
17 
18 ll n, m, k, p;
19 ll POW(ll base, ll num) {
20     ll ret = 1;
21     while (num) {
22         if (num & 1) (ret *= base) %= p;
23         (base *= base) %= p;
24         num >>= 1;
25     }
26     return ret;
27 }
28 int main() {
29     scanf("%lld%lld%lld%lld", &n, &k, &m, &p);
30     ll ans1 = n % p;
31     (ans1 *= POW(m , k - 1)) %= p; 
32     ll ans2 = (m * (m + 1) / 2) % p;
33     (ans2 *= POW(m, k - 2)) %= p;
34     (ans2 *= k - 1) %= p;
35     printf("%lld", ((ans1 - ans2) % p + p) % p);
36     return 0;
37 }
View Code

 

 

遊走

  題目: http://www.lydsy.com/JudgeOnline/problem.php?id=3143

  題解:

    首先貪心,編號小的通過次數必定多,那麼咱們只須要求出每一條邊的通過次數便可,由於是等可能的,那麼這個很差求的通過求每個點的通過次數$P_{i}$,那麼每一條邊$(x,y)$的通過次數$G_{i}=\frac{P_{x}}{degree_{x}}+\frac{P_{y}}{degree_{y}}$

    那麼問題轉化爲了如何求解$P_{i}$

    咱們發現$P_{i}=\sum_{\forall(x,i)}\frac{P_{x}}{degree_{x}}+\sum_{\forall(i,x)}\frac{P_{x}}{degree_{x}}$

    可是有特殊狀況$P_{1}=\sum_{\forall(x,i)}\frac{P_{x}}{degree_{x}}+\sum_{\forall(i,x)}\frac{P_{x}}{degree_{x}}+1$

           $P_{n}=1$

    那麼很明顯了,高斯消元,有一個地方須要注意,在消元之中,$P_{n}$應該置爲0,應爲只要到達n是出不來的。

  $1^{-10}$才過。。。好像long double直接過的樣子。。。

 1 #include <bits/stdc++.h>
 2 #define rep(i, a, b) for (int i = a; i <= b; i++)
 3 #define drep(i, a, b) for (int i = a; i >= b; i++)
 4 #define REP(i, a, b) for (int i = a; i < b; i++)
 5 #define mp make_pair
 6 #define pb push_back
 7 #define xx first
 8 #define yy second
 9 #define eps 1e-10
10 using namespace std;
11 typedef long long ll;
12 typedef pair<int, int> pii;
13 const int inf = 0x3f3f3f3f;
14 const ll INT = 0x3f3f3f3f3f3f3f3fll;
15 template <typename T> void Max(T &a, T b) { if (a < b) a = b; }
16 template <typename T> void Min(T &a, T b) { if (a > b) a = b; }
17 //******************************************************************
18 
19 const int maxn = 505, maxm = 250005;
20 
21 double eq[maxn][maxn];
22 pii E[maxm]; int ed_tot;
23 int deg[maxn];
24 double A[maxm], val[maxn];
25 
26 void gauss(int m, int n) {
27     rep(i, 1, n) {
28         if (fabs(eq[i][i]) < eps) rep(j, i, m) { if (fabs(eq[j][i]) > eps) swap(eq[i], eq[j]); break; }
29         rep(j, i + 1, n + 1) eq[i][j] /= eq[i][i];
30         eq[i][i] = 1;
31         rep(j, 1, m) if (i != j && fabs(eq[j][i]) > eps) {
32             double t = eq[j][i];
33             rep(k, i, n + 1) eq[j][k] -= t * eq[i][k];
34         }
35     }
36     rep(i, 1, m) val[i] = eq[i][n + 1];
37 }
38 
39 int main() {
40     int n, m; scanf("%d%d", &n, &m);
41     rep(i, 1, m) {
42         int x, y; scanf("%d%d", &x, &y);
43         E[++ed_tot] = mp(x, y);
44         deg[x]++, deg[y]++;
45     }
46     rep(i, 1, m) {
47         eq[E[i].xx][E[i].yy] = 1.0 / deg[E[i].yy];
48         eq[E[i].yy][E[i].xx] = 1.0 / deg[E[i].xx];
49     }
50     rep(i, 1, n) eq[n][i] = 0;
51     eq[1][n + 1] = -1;
52     rep(i, 1, n) eq[i][i] = -1;
53     gauss(n, n);
54     //val[n] = 1;
55     rep(i, 1, m) {
56         A[i] += val[E[i].xx] / deg[E[i].xx];
57         A[i] += val[E[i].yy] / deg[E[i].yy];
58     }
59     sort(A + 1, A + 1 + m);
60     double ans(0);
61     rep(i, 1, m) ans += (m - i + 1) * A[i];
62     printf("%.3lf\n", ans);
63     return 0;
64 }
View Code

 

 

切糕

  題目: http://www.lydsy.com/JudgeOnline/problem.php?id=3144

  題解:

    題意有點搞笑還覺得是一個平面。

    其實是對於P*Q的每個豎列,選一個幹掉就能夠了。

    哈哈哈哈哈,網絡流經典模型。

    注意,如下$(x,y,z)$均表示第x層y行z列。

    首先考慮沒有D限制的狀況,對於每個點,對它的上一層建它的邊權的點,即$(x, y, z)\to(x-1,y,z)\quad v(x,y,z)$

    這樣須要多的一層,沒問題吧。若是割掉一條邊相對應着選了一個點那麼最小割是答案對吧。。。

    

    考慮有D的狀況。

    咱們必須對割進行限制,怎麼作呢?

    連邊

    $ \forall(x,y,z) \to(x-D,Y,Z) \quad (x-D \le0)&&|Y-y|+|X-x| \le1$

    

    來舉個例子,假設$D=2$,我如今選擇$(4,5,6)$這個點,和選擇這個點有關的邊有$(7,6,6)\to(5,5,6)$$(4, 5, 6)\to(2,6,6)$

    對$(4, 5, 6)\to(2,6,6)$連邊,這樣連邊之後從$(4,5,6)$就沒法走到$(1,6,6)$這樣的點了,應爲這樣構不成一個割。

    那它的上限是怎麼肯定的呢?是$(7,6,6)\to(5,5,6)$來阻隔的,這樣就不能讓它選擇大於D的點,不然構不成割,如圖三。

    圖中左邊的列表示$(x,5,6)$,右邊的列表示$(x,6,6)$的列。

相關文章
相關標籤/搜索