• 2018/8/10 部分枚举(类似尺取)


    题意:n个点,找出一个矩形,使其边界上包含尽量多的点。

    思路:1.部分枚举 -> 枚举上下界(将n个点的纵坐标单独排序)。

               2.枚举n个点 -> 枚举k条竖线(按照横坐标排序)。

               3.ans = max{ lef[ i ] - lef[ j ] + on[ j ] + on2[ i ] }, 显然要取最大的 “- lef[ j ] + on[ j ]” , 维护该最大值(M)该问题可以O(n)解决。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int N = 100+5;
     5 int n, y[N], lef[N], on[N], on2[N];
     6 struct point{
     7     int x, y;
     8     bool operator<(const point& other)const{
     9         return x < other.x;
    10     }
    11 }p[N];
    12 
    13 int solve(){
    14     int ans = 0;
    15     sort(y, y + n);
    16     sort(p, p + n);
    17     int m = unique(y, y+n) - y;
    18     if(m <= 2) return n;
    19     for(int a = 0; a < m; a++){
    20         for(int b = a+1; b < m; b++){
    21             int ymin = y[a], ymax = y[b], k = 0;///a new up and low.
    22             lef[k] = on[k] = on2[k] = 0;
    23             for(int i = 0; i < n; i++){
    24                 if(i == 0 || (p[i].x != p[i-1].x)){///a new line.
    25                     k++;
    26                     on[k] = on2[k] = 0;
    27                     lef[k] = lef[k-1]+on2[k-1]-on[k-1];
    28                 }
    29                 if(p[i].y > ymin && p[i].y < ymax) on[k]++;
    30                 if(p[i].y >= ymin && p[i].y <= ymax) on2[k]++;
    31             }
    32             if(k <= 2) return n;///i=0...n-1 -> <=2 -> n.
    33             int M = 0;
    34             for(int i = 1; i <= k; i++){///i=1...k
    35                 ans = max(ans, lef[i]+on2[i]+M);
    36                 M = max(M, on[i]-lef[i]);
    37             }
    38         }
    39     }
    40     return ans;
    41 }
    42 
    43 int main()
    44 {
    45     int kase = 0;
    46     while(~scanf("%d", &n) && n){
    47         for(int i = 0; i < n; i++){
    48             scanf("%d %d", &p[i].x, &p[i].y);
    49             y[i] = p[i].y;
    50         }
    51         printf("Case %d: %d
    ", ++kase, solve());
    52     }
    53     return 0;
    54 }
    怎么办还是满脑子暴力QAQ。。。

    A - And Then There Was One

     UVALive - 3882

    题意:约瑟夫环问题变形,n个人围坐一圈按序号排排好,第一次删除序号为m的老哥,之后每数k个人删除一次,求幸存者的序号。

    思路:1.递推!    f[ n ] = (f[ n - 1 ] + k) %n.  (f[ n ]表示共n个人时,幸存者的序号)n个人从 0 数到 k - 1 删去一个后(即为f[ n - 1]时的情形),从第k个人开始从 0 ~ n - 1 编号, 那么偏移就是 k - 0, f[ 0 ] = 0。复杂度O(n)。

               2.为了计算方便把序号减一,那么第一次本应删去的是序号为(k - 1)的老哥,因此偏移为 m - (k-1), 然后再把序号加一即可。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     int n, m, k, ans;
     7     while(~scanf("%d%d%d", &n,&k,&m) && (n||m||k)){
     8         ans = 0;
     9         for(int i = 2; i <= n; i++) ans = (ans + k) %i;
    10         ans = (ans + m-(k-1)) %n;
    11         if(ans <= 0) ans += n;
    12         printf("%d
    ", ans);
    13     }
    14     return 0;
    15 }
    递推

    B - Prince and Princess

     UVA - 10635 

    题意:求A、B的LCS,两个序列的长度超级无敌巨长!但是!系列中无重复元素!!!

    思路:1.由于序列长度可达250^2=62500,O(mn)的LCS解法显然行不通。

               2.序列中无重复元素,给A中每个元素编号,然后将B的元素按A的编码方式保存,于是就转化为LIS问题,可O(nlogn)解决!!!

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int inf = 1e9+7;
     5 const int N = 250 * 250;
     6 int n, p, q, d[N], id[N], b[N], g[N];
     7 
     8 int main()
     9 {
    10     int t, x, kase = 0;
    11     scanf("%d", &t);
    12     while(t--){
    13         memset(id, 0, sizeof(id));
    14         scanf("%d%d%d", &n,&p,&q);
    15         for(int i = 1; i <= p+1; i++){
    16             scanf("%d", &x);
    17             id[x] = i;
    18         }
    19         p = 0;
    20         for(int i = 1; i <= q+1; i++){///q+1...+1...
    21             scanf("%d", &x);
    22             if(id[x]) b[p++] = id[x];
    23         }
    24         int ans = 0;
    25         memset(g, inf, sizeof(g));
    26         for(int i = 0; i < p; i++){
    27             int pos = lower_bound(g+1, g+p+1, b[i]) - g;
    28             d[i] = pos;
    29             g[pos] = b[i];
    30             ans = max(ans, d[i]);
    31         }
    32         printf("Case %d: %d
    ", ++kase, ans);
    33     }
    34     return 0;
    35 }
    LCS(O(mn))->LIS(O(nlogn))!!!

    C - Game of Sum

     UVA - 10891

    题意:从左侧或右侧取数,两个人都尽力使自己取得数的和最大,问sumA-sumB。

    思路:总和一定,一人得分越高另一人得分就越低,因此无论怎么取,任意时刻游戏的状态都是原始序列的一段连续子序列。。。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int N = 100+5;
     5 int A[N], d[N][N], f[N][N], g[N][N], s[N];
     6 
     7 int main()
     8 {
     9     int n;
    10     s[0] = 0;
    11     while(~scanf("%d", &n) && n){
    12         for(int i = 1; i <= n; i++){
    13             scanf("%d", &A[i]);
    14             s[i] = s[i-1] + A[i];
    15         }
    16         for(int i = 1; i <= n; i++) d[i][i] = f[i][i] = g[i][i] = A[i];
    17         for(int L = 1; L < n; L++){
    18             for(int i = 1, j; i+L <= n; i++){
    19                 j = i+L;
    20                 int m = min(f[i+1][j], min(0, g[i][j-1]));
    21                 d[i][j] = s[j] - s[i-1] - m;
    22                 f[i][j] = min(d[i][j], f[i+1][j]);
    23                 g[i][j] = min(d[i][j], g[i][j-1]);///gggggggggggggg...
    24             }
    25         }
    26         printf("%d
    ", (d[1][n]<<1) - s[n]);
    27     }
    28     return 0;
    29 }
    记忆化搜索->递推

    明明已经看了lrj的代码还是顺手把数组名g写成f wa了一发。。。

  • 相关阅读:
    什么是restful风格?
    android中设置控件获得焦点
    Android中Parcelable的原理和使用方法
    webstorm快捷键大全
    HTTP状态码
    三行代码写爬虫
    HTTrackPortable
    安装mac系统
    Vue常用的操作指令
    什么样的人不适合当程序员呢?
  • 原文地址:https://www.cnblogs.com/curieorz/p/9453474.html
Copyright © 2020-2023  润新知