码迷,mamicode.com
首页 > 其他好文 > 详细

TC SRM 605

时间:2015-04-06 16:55:14      阅读:127      评论:0      收藏:0      [点我收藏+]

标签:

Div2  AlienAndSetDiv2   1000 pts

题意:1~2N的数分成2个数组A,B,并且数组中按增序排列,同时满足|A[i] - B[i]| <= K,问有多少种方法?

分析:从大到小依次决定每个数的放置位置,每次可以放在A或B中剩余的较高位置,当决定第i个数时,i+K+1,应该是已经匹配了,

那么只剩下i+1~i+K最多K个数处于未匹配的位置,用一个整数st表示,那么对于第i个数的转移情况,可以放置在某个数组中,

使他处于未匹配状况或者让他匹配.

dp[i][st]表示i个数需要划分,且i+1~i+K+1的未匹配情况用st的表示的方案数.

代码:

技术分享
 1 const int MOD = (int)1e9 + 7;
 2 const int maxn = 55*2;
 3 const int maxm = (1<<10) + 10;
 4 int dp[maxn][maxm];
 5 
 6 class AlienAndSetDiv2{
 7         public:
 8         int K, N, M;
 9         int dfs(int n, int st) {
10             int &res = dp[n][st];
11             if (res != -1) return res;
12             res = 0;
13             if (st&(1<<(K-1))) {
14                    res = dfs(n-1, (st<<1) % M);
15             } else {
16                    if (st == 0) {
17                        res = dfs(n-1, 1);
18                    } else {
19                        res = dfs(n-1, st<<1|1);
20                        int highBit = K-1;
21                        while (!((1<<highBit) & st)) highBit--;
22                        res = (res + dfs(n-1, (st^(1<<highBit))<<1)) % MOD;
23                    }
24             }
25             if (st == 0)  res = res*2%MOD;
26             return res;
27         }
28         int getNumber(int N, int K) {
29     memset(dp, -1, sizeof dp);
30     dp[0][0] = 1;
31     for (int i = 1; i < maxm; i++) dp[0][i] = 0;
32     M = (1<<K);
33     this->K = K;
34     this->N = N;
35 
36     return dfs(2*N, 0);
37         }
38 };
View Code

 

Div1 AlienAndHamburgers  250pts

题意:n种物品,每种物品有两个值taste[i],type[i]分别表示其美味值和类型,要求从中选出一些物品,使得类型数*美味值总和最大.

分析: 按类型排序,将类型相同的物品安排在连续一段考虑,对于第i个物品,如果选中,需要考虑前面一个选中的物品j, 及之前选中的类型总数,

如果j的类型和i的类型不同,那么选中前一个物品j的时候,选中的类型数比当前少1;否则就和当前类型数目一样.

设立状态表示dp[i][x][y] 表示选中第i的时候,选中的类型为x,选择的类型数为y的最大值.

代码:

技术分享
 1 typedef long long LL;
 2 typedef unsigned US;
 3 typedef pair<int, int> PII;
 4 typedef map<PII, int> MPS;
 5 typedef MPS::iterator IT;
 6 const int maxn = 55;
 7 int dp[maxn][maxn][maxn];
 8 int vis[110];
 9 bool mark[maxn][maxn][maxn];
10 int cnt;
11 struct Node {
12   int val, t;
13   Node() {}
14   Node (int val, int t) {
15     if (!vis[t]) {
16       vis[t] = ++cnt;
17     }
18     this->t = vis[t];
19     this->val = val;
20   }
21   bool operator < (const Node &o) const {
22     return t < o.t;
23   }
24 } a[maxn];
25 class AlienAndHamburgers {
26 public:
27   int n;
28   int dfs(int pos, int x, int y) {
29     int &res = dp[pos][x][y];
30     if (mark[pos][x][y]) return res;
31     mark[pos][x][y] = true;
32     res = -inf;
33     if (x == 0 || y == 0) return res;
34     for (int i = 0; i < pos; i++) {
35       int nx = a[i].t;
36       int ny = y - !(nx == x);
37       int z = dfs(i, nx, ny);
38       if (res < (z == -inf ? 1LL * -inf :  (ny == 0 ? 1LL * y * a[pos].val : (0LL + z / ny + a[pos].val) * y)))
39         res = (z == -inf ? 1LL * -inf :  (ny == 0 ? 1LL * y * a[pos].val : (0LL + z / ny + a[pos].val) * y));
40     }
41     return res;
42   }
43 
44   int getNumber(vector <int> type, vector <int> taste) {
45     // memset(dp, -1, sizeof dp);
46     memset(mark, false, sizeof mark);
47 
48     cnt = 0;
49     for (int i = 0; i < maxn; i++) {
50       for (int j = 0; j < maxn; j++) {
51         for (int k = 0; k < maxn; k++)
52           dp[k][i][j] = -inf;
53         mark[0][i][j] = true;
54       }
55     }
56     dp[0][0][0] = 0;
57 
58     memset(vis, 0, sizeof vis);
59 
60     n = (int)type.size();
61 
62     for (int i = 0; i < n;  i++) {
63       a[i + 1] = Node(taste[i], type[i]);
64     }
65     a[0].t = a[0].val = 0;
66     sort(a + 1, a + n + 1);
67     int ans = 0;
68     for (int i = 1; i <= n; i++)
69       for (int j = 1; j <= a[i].t; j++)
70         ans = max(ans, dfs(i, a[i].t, j));
71     return ans;
72   }
73 };
View Code

 

Div1 AlienAndSetDiv1    450pts

题意:Div2 1000pts升级版,不同的是题目条件|A[i]-B[i]| <= K 变成了|A[i]-B[i]| >= K.不过分析过程还是差不多的.

分析:同样的从2N 到1按照从大到小的顺序进行安排,从A,B的高位往下进行放置.由于两个数要相差K以上才能配对,因此当考虑第i个数的时候,

对于尚未配对且满足>=i+K的数此时是可以和剩下的任意数配对的,而i+1~i+K-1之间的数时需要继续等待的,因此此时状态表示变成了dp[i][st][j],表示

分配剩下的i个数时,>=i+K的个数有j个,i+1~i+K-1之间的状态是st,这样只需要建立状态转移即可.

代码:

技术分享
 1 const int maxn = 100 + 10;
 2 const int maxm = (1 << 10) + 10;
 3 const int MOD =  1000000007;
 4 
 5 int dp[maxn][maxn][maxm];
 6 
 7 class AlienAndSetDiv1 {
 8 public:
 9     int N, K, M;
10     int dfs(int n, int m, int st) {
11         int &res = dp[n][m][st];
12         if (res != -1) return res;
13         res = 0;
14         if (K == 1) {
15             res = dfs(n - 1, m + 1, 0);
16             if (m > 0)
17                 res = (res + dfs(n - 1, m - 1, 0)) % MOD;
18         } else {
19             if (st == 0) {
20                 if (m == 0) {
21                     res = dfs(n - 1, K == 1, K != 1);
22                 } else {
23                     res = dfs(n - 1, m - 1, 0);
24                     res = (res + dfs(n - 1, m + (K == 1), K != 1)) % MOD;
25                 }
26             } else {
27                 if (m == 0) {
28                     res = dfs(n - 1, ((st & (1 << (K - 2))) != 0) + (K == 1), (st << 1 | (K != 1)) % M);
29 
30                 } else {
31                     res = dfs(n - 1, m - 1 +  ((st & (1 << (K - 2))) != 0), (st << 1) % M);
32                     res = (res + dfs(n - 1, m + (K == 1) + ((st & (1 << (K - 2))) != 0), (st << 1 | (K != 1)) % M)) % MOD;
33                 }
34             }
35         }
36         if (st == 0 && m == 0) res = res * 2 % MOD;
37         return res;
38     }
39     int getNumber(int N, int K) {
40         memset(dp, -1, sizeof dp);
41         for (int i = 0; i < maxn; i++)
42             for (int j = 0; j < maxm; j++)
43                 dp[0][i][j] = 0;
44         dp[0][0][0] = 1;
45         M = 1 << (K - 1);
46         this->N = N;
47         this->K = K;
48         return dfs(2 * N, 0, 0);
49     }
50 };
View Code

 

Div1 AlienAndPermutation 1000pts

题意:给定一个数组P为1~N数字的排列,最多可以进行K次操作:每次选取一个区间,将区间中的数替换成该区间内的数的最大值,最后能够得到不同的数组S.

分析:要解决这个题目首先要发现操作后的数组的性质,

1. S中满足S[j] = P[i]的位置构成连续序列

2. P[i]和P[j]的连续序列在S中相对位置不变

3. P[i]在S中的连续序列l~r满足对于任意处于l~r范围内的jP[j] <= Pi]

4. 对于操作后的序列S,有多少不同的值则需要多少次操作,这其中应该除开长度为1,且i = j的那些元素构成的序列.

下面设立状态表示f(i, j, k, d)表示已经决定P中前i个元素在S中的位置,S中前j个位置已经被占领,剩下k次操作的方案数,当然每个P[i]值最多算做一次操作,用一维d记录是否已经消耗了操作.

j = n 时,res = 1

否则如果i = n,res = 0.

其他情况:

如果S[j]不等于P[i]的值,转移到f(i+1, j, k, 0);否则

对于d = 1 or i == j,转移到f(i, j+1, k, d), 否则f(i, j+1, k-1, 1).

代码:

技术分享
 1 typedef long long LL;
 2 typedef unsigned US;
 3 typedef pair<int, int> PII;
 4 typedef map<PII, int> MPS;
 5 typedef MPS::iterator IT;
 6 const int MOD = 1000000007;
 7 const int maxn = 222;
 8 int dp[maxn][maxn][maxn][2];
 9 int l[maxn], r[maxn];
10 
11 class AlienAndPermutation{
12         public:
13         int n, K;
14         int dfs(int x, int y, int k, int d) {
15             int &res = dp[x][y][k][d];
16             if (res != -1) return res;
17             if (y == n) return res = 1;
18             if (x == n) return res = 0;
19             res = 0;
20             res = dfs(x+1, y, k, 0);
21             if (l[x] <= y && y <= r[x]) {
22                 if (d == 1 || x == y)
23                 res = (res + dfs(x, y+1, k, d)) % MOD;
24                 else if (k > 0) res = (res + dfs(x, y+1, k-1, 1)) % MOD;
25             }
26             return res;
27         }
28         int getNumber(vector <int> P, int K) {
29            n = (int)P.size();
30            this->K = K;
31            memset(dp, -1, sizeof dp);
32            for (int i = 0; i < n; i++) {
33                l[i] = r[i] = i;
34                while (l[i] - 1 >= 0 && P[l[i]-1] <= P[i]) l[i]--;
35                while (r[i]+1 < n && P[r[i]+1] <= P[i])  r[i]++;
36            }
37            return dfs(0, 0, K, 0);
38         }
39 };
View Code

 

 

代码:

TC SRM 605

标签:

原文地址:http://www.cnblogs.com/rootial/p/4395984.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!