标签:
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 };
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 };
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 };
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 };
代码:
标签:
原文地址:http://www.cnblogs.com/rootial/p/4395984.html