zoukankan      html  css  js  c++  java
  • TC SRM 605

    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

    代码:

  • 相关阅读:
    (转)Java中金钱的类的计算
    (转)如何实现删除重复记录并且只保留一条?
    MAXIMO-IBM文件夹的笔记
    maximo功能修改笔记
    maximo功能修改(初步理解)
    如何将两张表查询的结果集和下一张表查询
    Birt 折腾一周总结
    一天天的sql总结
    maximo弹框设置新的功能测试总结
    关于对 maximio平台的五个常用类的初步理解及总结
  • 原文地址:https://www.cnblogs.com/rootial/p/4395984.html
Copyright © 2011-2022 走看看