个人比赛总结(坑

存题处 

/******************/ 

为了迎接社会主义现代化建设所必须要的技术:

1、尺取法

2、反转法

3、弹性碰撞

4、折半枚举

5、坐标离散化

 

一、动规

1.概率dp

URAL 1776 Anniversary Firework

思路:此题直接求期望太过复杂。因为期望等于所有可能答案的概率与该答案的值的乘积的累加和,所以,我们可以求对于每个可能答案的概率,由此简化问题。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <vector>
 4 #include <cstring>
 5 
 6 const int N = 400 + 10;
 7 double d[N][N], sum[N][N];
 8 
 9 int main() {
10     int n;
11     scanf("%d", &n);
12     n -= 2;
13 
14     memset(d, 0sizeof d);
15     memset(sum, 0sizeof sum);
16 
17     d[0][0] = 1.;
18     for (int j = 0; j <= n; ++j)
19         sum[0][j] = 1.;
20 
21     for (int i = 1; i <= n; ++i) {
22         for (int j = 0; j <= i - 1; ++j) {
23             int l = j, r = i - 1 - j;
24             int t = std::max(l, r) + 1;
25 
26             for (int k = 1; k <= t; ++k) {
27                 d[i][k] += (d[l][k - 1] * sum[r][k - 1] + d[r][k - 1] * sum[l][k - 1] - d[l][k - 1] * d[r][k - 1]) / i;
28             }
29 
30             for (int j = 1; j <= n; ++j)
31                 sum[i][j] = sum[i][j - 1] + d[i][j];
32         }
33     }
34 
35     double ans = 0;
36     for (int j = 1; j <= n; ++j)
37         ans = ans + d[n][j] * j * 10;
38 
39     printf("%.8f\n", ans);
40     return 0;
41 }
View Code 

2.树形dp 

CodeForces 208B Solitaire 

题意:n张牌,如果第i张牌与第i-1或者第i-3张牌花色一样或者数字一样,那么可以将这两张牌合并,合并后,第i张牌覆盖合并的牌。

问将n张牌合并成一张牌是否可能。n <=52。 

思路:dp(i,a,b,c)//前i张牌,第i张是c,第i-1张是b,第i-2张是c时是否可以合并成功

 

3.朴素dp

二、图论 

1.最短路

2.网络流

URAL 1774 Barber of the Army of Mages

三、数据结构

1.并查集 

SGU 336 Elections

2.树状数组

UVA 12429 Finding Magic Triplets

题意:对于给定的n和K,要求满足a+b*b=c*c*c(mod K) ——(1<=a<=b<=c<=n)的组合数

方法:我们发现,当我们固定b的时候,左侧是一个连续的区间,我们可以预先将右侧的值存入树状数组,然后询问区间和即可。

要注意把握连续区间这一特点,还有固定中间值这个方法 

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 typedef long long ll;
 5 #define lson l, mid, rt << 1
 6 #define rson mid + 1, r, rt << 1 | 1
 7 const int N = 100000 + 10;
 8 int T = 0;
 9 
10 ll sum[N];
11 int K;
12 
13 void add(int pos, ll v) {
14     if (pos == 0) sum[0] += v;
15     else {
16         for (;pos < K; pos += pos & -pos)
17             sum[pos] += v;
18     }
19 }
20 ll query(int pos) {
21     if (pos < 0return 0;
22     else {
23         ll re = sum[0];
24         for (;pos > 0; pos -= pos & -pos)
25             re += sum[pos];
26         return re;
27     }
28 }
29 inline ll Q(int L, int R) {
30     return query(R) - query(L - 1);
31 }
32 void work() {
33     int n;
34     memset(sum, 0sizeof(ll) * K);
35     scanf("%d%d", &n, &K);
36 
37     int l, r, v;
38     ll ans = 0;
39     for (int b = n; b >= 1; --b) {
40         v = (ll)b * b * b % K;
41         add(v, 1);
42 
43         v = (ll)b * b % K;
44         if (K > b) {
45             l = 1; r = b;
46             l = (l + v) % K; r = (r + v) % K;
47             if (r < l) {
48                 ans += Q(0, r) + Q(l, K - 1);
49             } else {
50                 ans += Q(l, r);
51             }
52         } else {
53             l = 0; r = K - 1;
54             l = (l + v) % K; r = (r + v) % K;
55             if (r < l) {
56                 ans += Q(0, r) * (b / K) + Q(l, K - 1) * (b / K);
57             } else {
58                 ans += Q(l, r) * (b / K);
59             }
60             if (b % K > 0) {
61                 l = 1; r = b % K;
62                 l = (l + v) % K; r = (r + v) % K;
63                 if (r < l) {
64                     ans += Q(0, r) + Q(l, K - 1);
65                 } else {
66                     ans += Q(l, r);
67                 }
68             }
69         }
70     }
71 
72     printf("Case %d: %lld\n", ++ T, ans);
73 }
74 int main() {
75     int cas;
76     scanf("%d", &cas);
77     while (cas -- > 0) {
78         work();
79     }
80     return 0;
81 }
View Code 

1990 MooFest

题意:给定n个pair型,对于每一对pair型,ans+=max(a.first,b.first) * abs(a.second - b.second),求最后的结果。

思路:按照first排序,然后树状数组维护

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 const int N = 200000 + 10;
 5 typedef long long ll;
 6 struct node {
 7     int pos;
 8     ll v;
 9 };
10 
11 node ar[N];
12 
13 struct Bit {
14     ll sum[N];
15     void clear() {
16         memset(sum, 0sizeof sum);
17     }
18     void add(int pos, ll v) {
19         if (pos == 0) sum[0] += v;
20         else {
21             for (;pos < N; pos += pos & -pos)
22                 sum[pos] += v;
23         }
24     }
25     ll query(int pos) {
26         if (pos < 0return 0;
27         else {
28             ll re = sum[0];
29             for (;pos > 0; pos -= pos & -pos)
30                 re += sum[pos];
31             return re;
32         }
33     }
34 };
35 
36 Bit a, b;
37 int n;
38 
39 bool cmp(const node& a, const node&  b) {
40     return a.v < b.v;
41 }
42 void work() {
43     a.clear(); b.clear();
44 
45     for (int i = 0; i < n; ++i)
46         scanf("%d%d", &ar[i].v, &ar[i].pos);
47 
48     std::sort(ar, ar + n, cmp);
49 
50     ll ans = 0, tot = 0;
51     for (int i = 0; i < n; ++i) {
52         ll w = a.query(ar[i].pos);
53         ll n1 = b.query(ar[i].pos);
54 
55         ans += (n1 * ar[i].pos - w) * ar[i].v + (tot - w - (i - n1) * ar[i].pos) * ar[i].v;
56 //        printf("%lld\n", ans);
57         a.add(ar[i].pos, ar[i].pos);
58         b.add(ar[i].pos, 1);
59 
60         tot = tot + ar[i].pos;
61     }
62 
63     printf("%lld\n", ans);
64 }
65 int main() {
66     while (1 == scanf("%d", &n)) {
67         work();
68     }
69     return 0;
70 }
View Code 

 

poj 3109 Inner Vertices

题意:给100000个黑色点,如果两对点的连线相交于一个白色点,则此点变成黑色。问最终会有多少个点。

思路:扫描线。

预处理:1,离散化坐标 2,找出所有最长垂直线段和水平线段 3,垂直线段按照x轴坐标分类 4,水平线段按照起点x轴坐标分类(3,4的线段放入vector中)

核心:1,枚举所有横坐标x,将所有起点坐标>=x的水平线段加入(在树状数组中更新其y坐标) 2,将所有终点坐标<x的水平线段删除(用优先队列维护,队首是终点最小;同时更新树状数组) 3,此时树状数组中所有的y值对应的水平线段都是横跨垂直线段x的,更新答案。

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <vector>
  5 #include <queue>
  6 typedef std::pair<intint> pii;
  7 const int INF = (int)(1e9) + 10;
  8 const int N = 100000 + 10;
  9 
 10 int X[N], idx, Y[N], idy;
 11 
 12 pii p[N];
 13 int n;
 14 
 15 std::vector<int> ar[N];
 16 std::vector<pii> b[N];
 17 int bra[N], brb[N];
 18 
 19 int sum[N];
 20 
 21 struct node {
 22     int x, y;
 23     node() {};
 24     node(int _x, int _y) {
 25         x = _x, y = _y;
 26     }
 27     friend bool operator < (const node& a, const node& b) {
 28         return a.x > b.x;
 29     }
 30 };
 31 std::priority_queue<node> Q;
 32 
 33 int t[N];
 34 
 35 void add(int pos, int v) {
 36     if (0 == pos) sum[0] += v;
 37     else {
 38         for (int i = pos; i < idy; i += i & -i)
 39             sum[i] += v;
 40     }
 41 }
 42 int query(int pos) {
 43     if (pos < 0return 0;
 44     int re = sum[0];
 45     for (int i = pos; i > 0; i -= i & -i)
 46         re += sum[i];
 47     return re;
 48 }
 49 
 50 inline int Qu(int L, int R) {
 51     return query(R) - query(L - 1);
 52 }
 53 void work() {
 54     for (int i = 0; i < n; ++i) {
 55         scanf("%d%d", &p[i].first, &p[i].second);
 56         X[i] = p[i].first; Y[i] = p[i].second;
 57     }
 58     std::sort(X, X + n); std::sort(Y, Y + n);
 59     idx = std::unique(X, X + n) - X; idy = std::unique(Y, Y + n) - Y;
 60 
 61     for (int i = 0; i < n; ++i) {
 62         p[i].first = std::lower_bound(X, X + idx, p[i].first) - X;
 63         p[i].second = std::lower_bound(Y, Y + idy, p[i].second) - Y;
 64     }
 65     //求出所有 垂直线
 66     for (int i = 0; i < idx; ++i) ar[i].clear();
 67     for (int i = 0; i < n; ++i)
 68         ar[p[i].first].push_back(p[i].second);
 69     for (int i = 0; i < idx; ++i)
 70         std::sort(ar[i].begin(), ar[i].end()); //a[x] (y1, y2)
 71 
 72     memset(brb, -1sizeof brb);
 73     std::fill(bra, bra + idy + 1, INF);
 74 
 75     for (int i = 0; i < n; ++i) {
 76         bra[p[i].second] = std::min(bra[p[i].second], p[i].first);
 77         brb[p[i].second] = std::max(brb[p[i].second], p[i].first);
 78     }
 79 
 80     for (int i = 0; i < idx; ++i) b[i].clear();
 81     for (int i = 0; i < idy; ++i)
 82     if (bra[i] < brb[i]) {
 83         b[bra[i]].push_back(pii(brb[i], i)); //b[x1] (x2, y)
 84     }
 85 
 86     while (!Q.empty()) Q.pop();
 87     memset(sum, 0sizeof sum);
 88     memset(t, 0sizeof t);
 89 
 90     int ans = 0;
 91     for (int i = 0; i < idx; ++i) {
 92         for (int j = 0; j < b[i].size(); ++j) {
 93             add(b[i][j].second, 1);
 94             ++ t[b[i][j].second];
 95             Q.push(node(b[i][j].first, b[i][j].second)); //(edx, y)
 96         }
 97         while (!Q.empty() && Q.top().x < i) {
 98             add(Q.top().y, -1);
 99             -- t[Q.top().y];
100             Q.pop();
101         }
102         if (ar[i].size() > 1) {
103             ans += Qu(ar[i][0], ar[i][ar[i].size() - 1]);
104             for  (int j = 0; j < ar[i].size(); ++j) {
105                 if (0 == t[ar[i][j]])
106                     ++ ans;
107             }
108         } else {
109             ans += ar[i].size();
110         }
111 
112     }
113     printf("%d\n", ans);
114 }
115 int main() {
116     while (1 == scanf("%d", &n)) {
117         work();
118     }
119     return 0;
120 }
View Code

四、贪心

POJ 2698 Servicing DVD Requests

五、数论

1.辗转相除法及其拓展应用

填数游戏

题意:p1(x1,y1)到p2(x2,y2)的线段上有多少个格点(x,y皆为整数) 

思路:gcd(x2-x1,y2-y1) - 1代表不连p1,p2时的答案。

x=x2-x1,y=y2-y1 ,假设答案是g,那么x,y都要可以整除g。所以g最大就是gcd(x,y)。

2.高斯消元

hdu 2262 Where is the canteen

http://blog.csdn.net/acm_cxlove/article/details/7905778

基础的高斯求概率。

设某点的期望步数为Ei。

那么目标的Ei=0。

Ei=(Enext1+Enext2……Enextk)/k+1。

整理下就是Enext1+Enext2……Enextk-k*Ei=-k

根据i点的后继结点nextj,那么从所有的后继结点走一步都可以到达i点。便是所有后继的期望平均值+1.

以此建立方程组,然后用高斯消元求解。

  1 #include <cstring>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <vector>
  5 #include <cmath>
  6 
  7 typedef std::vector<double> vec;
  8 typedef std::vector<vec> mat;
  9 const double eps = 1e-8;
 10 
 11 vec gauss_jordan(const mat& A, const vec& b) {
 12     int n = A.size();
 13     mat B(n, vec(n + 1));
 14     for(int i = 0; i < n; ++i)
 15         for (int j = 0; j < n; ++j)
 16             B[i][j] = A[i][j];
 17     for (int i = 0; i < n; ++i) B[i][n] = b[i];
 18 
 19     for (int i = 0; i < n; ++i) {
 20         int pivot = i;
 21         for (int j = i; j < n; ++j) {
 22             if (abs(B[j][i]) > abs(B[pivot][i])) pivot = j;
 23         }
 24         std::swap(B[i], B[pivot]);
 25 
 26         //有无穷解或者无解
 27         if (abs(B[i][i]) < eps) return vec();
 28 
 29         //吧正在处理的未知数的系数变成1
 30         for (int j = i + 1; j <= n; ++j) B[i][j] /= B[i][i];
 31         for (int j = 0; j < n ;++j) {
 32             if (i != j) {
 33                 for (int k = i + 1; k <= n; ++k)
 34                     B[j][k] -= B[j][i] * B[i][k];
 35             }
 36         }
 37     }
 38     vec x(n);
 39     for (int i = 0; i < n; ++i) x[i] = B[i][n];
 40     return x;
 41 }
 42 
 43 const int dx[] = {10, -10};
 44 const int dy[] = {010, -1};
 45 const int M = 15 + 1;
 46 
 47 char s[M][M];
 48 bool vis[M][M];
 49 
 50 int r, c;
 51 
 52 void dfs(int x, int y) {
 53     vis[x][y] = true;
 54     for (int dir = 0; dir < 4; ++dir) {
 55         int nx = x + dx[dir], ny = y + dy[dir];
 56         if (nx >= 0 && nx < r && ny >= 0 && ny < c && !vis[nx][ny]) {
 57             if (s[nx][ny] == '.')
 58                 dfs(nx, ny);
 59             else if (s[nx][ny] == '$')
 60                 vis[nx][ny] = true;
 61         }
 62     }
 63 }
 64 void work() {
 65     int sx, sy;
 66     for (int i = 0; i < r; ++i) {
 67         scanf("%s", s[i]);
 68         for (int j = 0; j < c; ++j)
 69         if (s[i][j] == '@') {
 70             sx = i; sy = j;
 71         }
 72     }
 73 
 74     memset(vis, 0sizeof vis);
 75 //    printf("%d %d\n", sx, sy);
 76     dfs(sx, sy);
 77 
 78     bool f = false;
 79     for (int i = 0; i < r; ++i)
 80         for (int j = 0; j < c; ++j)
 81             if (s[i][j] == '$' && vis[i][j])
 82                 f = true;
 83     if (f) {
 84         mat A(r * c, vec(r *c, 0));
 85         vec b(r * c, 0);
 86 
 87         for (int i = 0; i < r; ++i)
 88         for (int j = 0; j < c; ++j) {
 89             if (s[i][j] == '$' || !vis[i][j]) {
 90                 A[i * c + j][i * c + j] = 1;
 91                 continue;
 92             }
 93 
 94             int moves = 0;
 95             for (int dir = 0; dir < 4; ++dir) {
 96                 int nx = i + dx[dir], ny = j + dy[dir];
 97                 if (nx >= 0 && nx < r && ny >= 0 && ny < c && vis[nx][ny]) {
 98                     ++moves;
 99                     A[i * c + j][nx * c + ny] = -1;
100                 }
101             }
102             b[i * c + j] = A[i * c + j][i * c + j] = moves;
103         }
104         vec x = gauss_jordan(A, b);
105         if (x.size() > 0 && fabs(x[sx * c + sy]) > eps) {
106             printf("%.6f\n", x[sx * c + sy]);
107         } else {
108             puts("-1");
109 //            printf("%.6f\n", x[sx * c + sy]);
110         }
111     } else {
112         puts("-1");
113     }
114 }
115 int main() {
116     while (2 == scanf("%d%d", &r, &c)) {
117         work();
118     }
119     return 0;
120 }
121 
122 
123 int q(n, m) {
124     if (m == 1return 1;
125     else if (m > n) return q(n, n);
126     else return q(n, m - 1) + q(n - m, m);
127 }
View Code 

/******************************华丽的分割线*******************************************/ 

 

炫酷算术魔法结社群赛系列(群号283513414)(举办者  ftiasch)

20130926 - 初级魔法练习

A:POJ 2443 Set Operation

题意:给我一个1000行,10000列的01矩阵,对于指定两列询问是否存在公共的1。

方法:压缩。对于给定两列,如果直接比较需要枚举1000位,我们可以每30位压缩成一个数,用二进制&运算代替枚举,则枚举次数就变成了1000/30 <= 34,起到了非凡的加速效果。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 
 5 const int N = 10000;
 6 const int M = 35;
 7 int b[N + 1][M];
 8 
 9 int n;
10 
11 bool check(int x, int y) {
12     for (int i = 0; i < M; ++i)
13         if ((b[x][i] & b[y][i]) > 0return true;
14     return false;
15 }
16 void work() {
17     memset(b, 0sizeof(b));
18 
19     int u, v;
20     for (int i = 0; i < n; ++i) {
21         scanf("%d", &u);
22         while (u -- > 0) {
23             scanf("%d", &v);
24             b[v][i / 30] |= 1 << (i % 30);
25         }
26     }
27     int Q, x, y;
28     scanf("%d", &Q);
29     while (Q -- > 0) {
30         scanf("%d%d", &x, &y);
31         if (check(x, y))
32             puts("Yes");
33         else
34             puts("No");
35     }
36 }
37 int main() {
38     while (1 == scanf("%d", &n)) {
39         work();
40     }
41     return 0;
42 }
View Code 

B:POJ 3244 Difference between Triplets

 

关于这个公式的解释,我们可以将I,J,K看成图上三个点,那么max{I, J, K} - min{I, J, K}就是一条线段的距离然后线性扫描即可。 

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 typedef long long ll;
 5 const int N = 200000;
 6 
 7 int ab[N], ac[N], bc[N];
 8 
 9 int n;
10 
11 void gao(ll& sum, int* num) {
12     for (int i = 1; i < n; ++i) {
13         sum = sum + (ll)(n - i) * i * (num[i] - num[i - 1]);
14     }
15 }
16 void work() {
17     int a, b, c;
18     for (int i = 0; i < n; ++i) {
19         scanf("%d%d%d", &a, &b, &c);
20         ab[i] = a - b; ac[i] = a - c; bc[i] = b - c;
21     }
22 
23     std::sort(ab, ab + n);
24     std::sort(bc, bc + n);
25     std::sort(ac, ac + n);
26 
27     ll sum = 0;
28     gao(sum, ab);
29     gao(sum, ac);
30     gao(sum, bc);
31 
32     printf("%lld\n", sum / 2);
33 }
34 int main() {
35     while (1 == scanf("%d", &n)) {
36         if (0 == n) break;
37         work();
38     }
39     return 0;
40 }
View Code 

20130929 - 火球术入门

A:POJ 3040 Allowance
B:POJ 3182 The Grove

20130930 - 风系魔法的基本要领

B:poj 3375 Network Connection

题意:有n台电脑,m个接口,每台电脑和接口都有属于自己的一维坐标,每个电脑都要选择一个接口连接,连接的代价是|Xi - Yj|。

n <= 2000, m <= 100000;

思路:首先O(N*M)的dp肯定可以轻松想到,d[i][j]//用前j个接口来满足前i台电脑后最小需要花费多少

这个算法复杂度太高,所以我们将它优化。我们先在Y中找最接近Xi的那个接口p,对于Xi这才是最佳答案,但是,他可能被其他接口占用,最多有n个接口会占用他,所以,上限是p+n,这个接口也可能要留给其他的接口用,所以,最多有n个接口在后面等着用这个接口,下限是p-n。由此,算法优化到了O(N^2)

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <cmath>
 5 typedef long long ll;
 6 const ll INF = 1ll << 60;
 7 
 8 const int N = 2000 + 10;
 9 const int M = 100000 + 10;
10 
11 ll d[N][N << 1];
12 
13 int L[N], R[N];
14 int n, m;
15 
16 int x[N], y[M];
17 
18 void work() {
19     for (int i = 1; i <= m; ++i)
20         scanf("%d", &y[i]);
21     for (int i = 1; i <= n; ++i)
22         scanf("%d", &x[i]);
23 
24     std::sort(x + 11 + x + n);
25     std::sort(y + 11 + y + m);
26 
27     for (int i = 1; i <= n; ++i) {
28         int p = std::lower_bound(y + 1, y + m + 1, x[i]) - y;
29         L[i] = std::max(1, p - n);
30         R[i] = std::min(m, p + n);
31     }
32 
33     for (int i = 0; i < N + N; ++i) d[1][i] = INF;
34     for (int i = L[1]; i <= R[1]; ++i) d[1][i - L[1]] = abs(x[1] - y[i]);
35 
36     for (int i = 2; i <= n; ++i) {
37         int k = L[i - 1];
38         ll v = INF;
39 
40         for (int j = L[i]; j <= R[i]; ++j) {
41             while (k <= R[i - 1] && k < j) {
42                 v = std::min(v, d[i - 1][k - L[i - 1]]);
43                 ++k;
44             }
45             d[i][j - L[i]] = std::min(INF, v + std::abs(x[i] - y[j]));
46             // printf("%d %d %d\n", x[i], y[j], d[i][j]);
47         }
48     }
49     ll mx = INF;
50     for (int i = L[n]; i <= R[n]; ++i)
51         mx = std::min(mx, d[n][i - L[n]]);
52 
53     printf("%I64d\n", mx);
54 }
55 int main() {
56     while (2 == scanf("%d%d", &m, &n)) {
57         work();
58     }
59     return 0;
60 }
View Code 

C:poj 3419 Difference Is Beautiful

20131001 - 我是如何成为一名合格的小学生的?

A:HDU 3552 I can do it!

题意:给我n个pair型元素,要求我们把他们分成两组(A,B两组),使得A组中first元素的最大值+B组中second元素的最大值的和最小

思路:按照first的值排序,然后枚举A组最大值,线性扫描即可

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 typedef std::pair<intint> pii;
 5 int T = 0;
 6 
 7 const int N = 100000 + 10;
 8 pii ar[N];
 9 
10 void work() {
11     int n;
12     scanf("%d", &n);
13     for (int i = 0; i < n; ++i) {
14         scanf("%d%d", &ar[i].first, &ar[i].second);
15     }
16 
17     std::sort(ar, ar + n);
18 
19     int ans = (int)(1e9) * 2 + 1;
20     int bmax = 0;
21     for (int i = n - 1; i >= 0; --i) {
22 //        printf("%d\n", ans);
23         ans = std::min(ans, ar[i].first + bmax);
24         bmax = std::max(bmax, ar[i].second);
25     }
26     printf("Case %d: %d\n", ++T, ans);
27 }
28 int main() {
29     int cas;
30     scanf("%d", &cas);
31     while (cas -- > 0) {
32         work();
33     }
34     return 0;
35 }
View Code 

B:HDU 3545 Board Coloring

题意:用0到255对一个4*N的格子染色,给定M组限制,对于(x1,y1,x2,y2),必须满足(x1,y1)和(x2,y2)两个格子的颜色一样,问有多少种染色方法。(N<=15)

思路:很神奇的dp题。因为要求x,y >= A x,y-1所以符合单调性。

d[x1][x2][x3][x4]//第一行已经染色了前x1格,第二行..

我们可以先预处理所有不可行的方案,然后每次更新后将这些情况的数值设置为0。

首先第一层是当前要涂的颜色。第二层表示当前要涂的行,从第1行到第4行。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <vector>
 5 #define REP(i, st, ed) for (i = st; i <= ed; ++i)
 6 const int mod = 100000;
 7 const int N = 15 + 1;
 8 const int M = 100 + 1;
 9 
10 int d[N][N][N][N];
11 bool legal[N][N][N][N];
12 
13 int x1[M], x2[M], y1[M], y2[M];
14 int n, m, t = 0;
15 
16 int p[4], to[4];
17 void prepare() {
18     int i;
19 
20     REP(p[0], 0, n)
21     REP(p[1], 0, n)
22     REP(p[2], 0, n)
23     REP(p[3], 0, n){
24         legal[p[0]][p[1]][p[2]][p[3]] = false;
25         REP(i, 1, m) {
26             if ((p[x1[i]] >= y1[i]) ^ (p[x2[i]] >= y2[i])) {
27                 legal[p[0]][p[1]][p[2]][p[3]] = truebreak;
28             }
29         }
30     }
31 }
32 void work() {
33     scanf("%d%d", &n, &m);
34     for (int i = 1; i <= m; ++i) {
35         scanf("%d%d%d%d", &x1[i], &y1[i], &x2[i], &y2[i]);
36         --x1[i]; --x2[i];
37     }
38 
39     prepare();
40 
41     memset(d, 0sizeof d);
42     d[0][0][0][0] = 1;
43 
44     for (int i = 1; i <= 256; ++i) {
45         for (int idx = 0; idx < 4; ++idx)
46         REP(p[0], 0, n)
47         REP(p[1], 0, n)
48         REP(p[2], 0, n)
49         REP(p[3], 0, n)
50         if (d[p[0]][p[1]][p[2]][p[3]] > 0 && p[idx] + 1 <= n) {
51             ++p[idx];
52             int& t = d[p[0]][p[1]][p[2]][p[3]];
53             --p[idx];
54             t += d[p[0]][p[1]][p[2]][p[3]];
55             if (t >= mod)
56                 t -= mod;
57         }
58         REP(p[0], 0, n)
59         REP(p[1], 0, n)
60         REP(p[2], 0, n)
61         REP(p[3], 0, n)
62         if (legal[p[0]][p[1]][p[2]][p[3]])
63             d[p[0]][p[1]][p[2]][p[3]] = 0;
64     }
65     printf("Case %d: %05d\n", ++t, d[n][n][n][n]);
66 }
67 int main() {
68     int cas;
69     scanf("%d", &cas);
70     while (cas -- > 0) {
71         work();
72     }
73     return 0;
74 }
View Code 

C:HDU 4014 Jimmy’s travel plan

 20131002 - 暴雨术入门

A:HDU 4103 Clock

B:HDU 4104 Discount

C:HDU 4107 Gangster

20131003 - 在沙漠中的长途旅行

A:POJ 2793 Cactus

B:POJ 3567 Cactus Reloaded

20130904 - 幽默术

A:POJ 3538 Domestic Networks

B:POJ 3566 Building for UN

C:POJ 3537 Crosses and Crosses

20131005 - 幽默大师职业赛

A:POJ 3208 Apocalypse Someday

B:POJ 3015 Expected Difference

C:POJ 3016 K-Monotonic

20131006 - 幽默大师卫冕战

A:SGU 409 Berland Flag

B:SGU 361 National Flag

C:SGU 379  Elevator
20131007 - 胜利大逃亡

A:SGU 527 Explode 'Em All

题意:在一个25*25的地图中放置炸弹,消灭所有的山。一个炸弹可以消灭所在行和所在列的所有山。

方法:搜索。假设我们已经选取了i行要放置炸弹,那么还有j行的山要消灭,那么这些山只能靠这i行的炸弹来消灭,如果剩下的炸弹所用的列小于等于i,那么答案就是i。根据这点深搜。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 const int N = 30;
 5 
 6 char s[N];
 7 int r, c;
 8 
 9 int sta[N], ans;
10 
11 void dfs(int idx, int sx, int cntx, int sy, int cnty) {
12     if (std::max(cntx, cnty) >= ans) return ;
13     if (idx == r) {
14         ans = std::min(ans, std::max(cntx, cnty));
15     } else {
16         if (sta[idx] > 0) {
17             int to = sy | sta[idx];
18             if (to == sy)
19                 dfs(idx + 1, sx, cntx, sy, cnty);
20             else {
21                 int cc = 0;
22                 for (int i = 0; i < c; ++i)
23                     if (to >> i & 1)
24                         ++cc;
25                 dfs(idx + 1, sx, cntx, to, cc);
26             }
27             dfs(idx + 1, sx | (1 << idx), cntx + 1, sy, cnty);
28         } else {
29             dfs(idx + 1, sx, cntx, sy, cnty);
30         }
31     }
32 }
33 void work() {
34     memset(sta, 0sizeof sta);
35 
36     for (int i = 0; i < r; ++i) {
37         scanf("%s", s);
38         for (int j = 0; j < c; ++j)
39             if (s[j] == '*')
40                 sta[i] |= 1 << j;
41     }
42 
43     ans = std::max(r, c);
44     dfs(00000);
45 
46     printf("%d\n", ans);
47 }
48 int main() {
49     while (2 == scanf("%d%d", &r, &c)) {
50         work();
51     }
52     return 0;
53 }
View Code 

B:CodeForces 37C Old Berland Language

C:CodeForces 40E Number Table

20131008 - 想不出名字了呜

A:HDU 3434 Sequence Adjustment

B:HDU 4275 Color the Tree

C:HDU 4270 Dynamic Lover

2013 ACM亚洲赛网络赛系列 

B:An Easy Problem for Elfness

E:Round Table

F:G(x)

H:Little Wish~ lyrical step~

杭州赛区:

D:Save Labman No.004

E:Pinball Game 3D

G:Starloop System

J: Mex

题解链接:http://www.cnblogs.com/hewifi/p/3329168.html

长春赛区:

A:Poker Shuffle

B:Good Firewall

H:Network

I:Bell

J: Flyer

二分不幸运的人所在的位置,由于不幸运的人只有一个,所以如果有人不幸运,那么任何从起点开始,终点>=此人位置的区间中,被发放的海报的总数一定是奇数,否则就一定是偶数,由此满足单调性。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <vector>
 5 typedef __int64 ll;
 6 const ll INF = 1ll << 32;
 7 const int N = 20000 + 10;
 8 
 9 ll a[N], b[N], c[N];
10 int n;
11 
12 bool judge(ll x) {
13     ll tot = 0;
14     for (int i = 0; i < n; ++i) {
15         if (x < a[i]) continue;
16         if (x >= b[i]) {
17             tot = tot + 1 + (b[i] - a[i]) / c[i];
18         } else {
19             tot = tot + 1 + (x - a[i]) / c[i];
20         }
21         tot = tot & 1;
22     }
23     return tot & 1;
24 }
25 void work() {
26     for (int i = 0; i < n; ++i)
27         scanf("%I64d%I64d%I64d", &a[i], &b[i], &c[i]);
28     ll l = 0, r = INF, mid;
29     while (r - l > 1) {
30         mid = (l + r) / 2;
31         if (judge(mid))
32             r = mid;
33         else
34             l = mid;
35     }
36 
37     if (judge(r)) {
38         int cnt = 0;
39         for (int i = 0; i < n; ++i) {
40             if (r < a[i] || r > b[i]) continue;
41             if ((r - a[i]) % c[i] == 0)
42                 ++cnt;
43         }
44         printf("%I64d %d\n", r, cnt);
45     } else
46         puts("DC Qiang is unhappy.");
47 }
48 int main() {
49     while (1 == scanf("%d", &n)) {
50         work();
51     }
52     return 0;
53 }
View Code  

 

 

6th BUPT Programming Contest Final

A:UESTC 1697 Palindrome Again

这一题本质上是求两个串有多少对公共回文子串,只考虑子串的起始位置和长度的不同。

E:UESTC 1701 PAC-Phone

给你两个点集问是否相似。

H:UESTC 1704 Running

I: UESTC 1705 The Longest Sequence of Rectangles

题意:n个矩形的lis,需要严格满足第i个矩形的左下角坐标严格大于第i-1个矩形的右上角坐标。

思路:树状数组\线段树。首先将所有点先按照x轴坐标从小到大排序,如果x轴坐标一样,那么终点总是在起点后面,如果是同一性质的点,为了严格递增,按照y轴坐标从大到小排序(如果是不严格则从小到大)。然后用树状数组或者线段树维护。如果遇到的是起点,则更新数组中的值,如果是终点,则将此点插入数据结构中。

 1 #include <cstring>
 2 #include <cstdio>
 3 #include <algorithm>
 4 struct node {
 5     int x, y, typ, id;
 6 };
 7 
 8 #define lson l, mid, rt << 1
 9 #define rson mid + 1, r, rt << 1 | 1
10 const int N = 200000 + 5;
11 
12 int val[N];
13 
14 node p[N];
15 int y[N], idy;
16 
17 int len[N];
18 int query(int R) {
19     int re = 0;
20     for (; R > 0; R -= R & -R) {
21         re = std::max(re, val[R]);
22     }
23     return re;
24 }
25 void update(int pos, int v) {
26     for (; pos <= idy; pos += pos & -pos)
27         val[pos] = std::max(val[pos], v);
28 }
29 bool cmp(const node& a, const node& b) {
30     if (a.x ^ b.x) return a.x < b.x;
31     else {
32         if (a.typ ^ b.typ) return a.typ < b.typ;
33         else return a.y > b.y;
34     }
35 }
36 void work() {
37     int n;
38     scanf("%d", &n);
39 
40     idy = 0;
41     for (int i = 0; i < n; ++i) {
42         scanf("%d%d", &p[i << 1].x, &p[i << 1].y);
43         p[i << 1].typ = 0;
44 
45         scanf("%d%d", &p[i << 1 | 1].x, &p[i << 1 | 1].y);
46         p[i << 1 | 1].typ = 1;
47 
48         p[i << 1 | 1].id = p[i << 1].id = i;
49 
50         y[idy ++] = p[i << 1].y;
51         y[idy ++] = p[i << 1 | 1].y;
52     }
53     std::sort(y, y + idy);
54     idy = std::unique(y, y + idy) - y;
55 
56     n <<= 1;
57     for (int i = 0; i < n; ++i) {
58         p[i].y = std::lower_bound(y, y + idy, p[i].y) - y + 1;
59     }
60 
61     memset(val, 0sizeof(int) * (idy + 2));
62 
63     int mx, ans = 1;
64 
65     std::sort(p, p + n, cmp);
66     memset(len, 0sizeof len);
67     for (int i = 0; i < n; ++i) {
68         if (0 == p[i].typ) {
69             len[p[i].id] = std::max(len[p[i].id], 1 + query(p[i].y - 1));
70             ans = std::max(ans, len[p[i].id]);
71         } else {
72             update(p[i].y, len[p[i].id]);
73         }
74     }
75     printf("%d\n", ans);
76 }
77 int main() {
78     int cas;
79     scanf("%d", &cas);
80     while (cas -- > 0) {
81         work();
82     }
83     return 0;
84 }
View Code 

 

ICPC Latin American Regional 2011 - South America/South 

C:UVALive 5791 Candy's Candy

题意: 

有f种口味的糖果,现在要把每颗糖果分到一些packs里面去。packs分两种:

flavored pack:只有一种口味。

variety pack:每种口味都有。

求满足下列要求的分法有多少种:

1、每个pack至少有两颗糖果。

2、所有pack的糖果数相同。

3、variety pack 里每种口味的糖果数量相同。

4、至少一个variety pack。

5、每种口味至少一个flavored pack。

D:UVALive 5792 Diccionário Portuñol

题意:给你两种串,一种可以当前缀,一种可以当后缀,问两种串合起来,一共有多少种组合。并且没有重合。

F:UVALive 5794 File Retrieval 

题意:给你n个串,现在有一个搜索系统,对于任意一个串s,它能够返回所有包含s这个子串的串的集合。

询问一共有多少种可能的返回集合。对于所有的串s。规模:60个串,每个串长度10^4。

 

posted @ 2013-10-09 19:05  masterhe  阅读(692)  评论(0编辑  收藏  举报