zoukankan      html  css  js  c++  java
  • SUMMARIZE 6.1

    SUMMARIZE 2019.6

    两个月里一直投入于搜索和树状数组里。我总喜欢写,却一直在重复已经掌握的东西。总是在有新的想法后急于去写出来,在出现bug之后想不通也没有完全解决。这样是永远不会有进步的。在考试的时候,纵使有n种思路,也没有一种完全畅通。

    我决定把所有搁置的题按照正解的思路做一遍。

    书架(树状数组 + 二分)

    仔细观察树状数组会发现,如果将末位扩大到2n,每一次二分查找都会切到二进制100...0的位置,再配合其规律把要找的答案随之修剪,便从O(nlog2n)优化到O(nlogn):

    书架

    题目描述】

    Knuth先生家里有个精致的书架,书架上有N本书,他又买来了M本不同的新书。现在他要把新买的书依次插入到书架中,他已经把每本书要插入的位置标记好了,并且相应的将它们放好。由于Knuth年龄已大,过几天他已经记不清某些位置上放的到底是什么书了,请问你能帮助他吗?

    输入文件】

    输入文件名:book.in

    输入文件:第一行为整数N,接下来N行分别是书架上依次放着的N本书的书名(书名由不含空格的字符串构成,长度不超过10)。下一行将要输入一个整数M,接下来的M行分别为这本书的书名和要插入的位置。下一行将要输入一个整数Q,接下来共有Q次询问,每行都是一个整数表示询问的位置。(书架上位置的编号从0开始)

    输出文件】

    输出文件名:book.out

    输出文件:输出Q行,每行对应着相应查询位置的书名。

    样例输入】

    3

    Math

    Algorithm

    Program

    2

    Picture 2

    System 1

    3

    0

    1

    3

    样例输出】

    Math

    System

    Picture

    【样例解释

    原来有三本书Math、Algorithm、System,后来又买了两本书,分别插入到2和1的位置,每次插入时其他书都要向后挪一个位置,最后书架上书的序列为:

    0  Math

    1  System

    2  Algorithm

    3  Picture

    4  Program

    Q次询问依次为0, 1, 3位置的书,所以答案为:Math、System、Picture

    数据约定】

    对于100%的数据,1 ≤ N ≤ 200,  1 ≤ M ≤ 10^5,  1 ≤ Q ≤ 10^4

    对于100%的数据都符合题目中所描述的限制关系,数据保证每次插入的位置均不超过当时书架上书的数量,而且保证Q次查询中的每个位置上一定有书。

     1 #include<iostream> 
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<string>
     5 using namespace std;
     6 struct node{
     7     string name;
     8     int num;
     9 }a[200005];
    10 int n, m, q, n1=1;
    11 int s[200005];
    12 string ans[200005];
    13 
    14 int lowbit(int x){
    15     return x & -x;
    16 }
    17 int getsum(int x){
    18     int ans=0;
    19     for(; x; x-=lowbit(x))
    20         ans+=s[x];
    21     return ans;
    22 }
    23 int update(int x, int y){
    24     for(; x<=n1; x+=lowbit(x))
    25         s[x]+=y;
    26 }
    27 int find(int y){
    28     int l=1, r=n1, mid;
    29     while(l < r-1){
    30         mid = (l + r) >> 1;
    31         if(s[mid] < y){
    32             y-=s[mid];
    33             l=mid+1;
    34         }else r=mid;
    35     }
    36     if(s[l] == y) return l;
    37     else return r;
    38 }
    39 int main(){
    40     freopen("book.in","r",stdin);
    41     ios::sync_with_stdio(false);
    42     cin >> n;
    43     for(int i=1; i<=n; i++){
    44         cin >> a[i].name;
    45         a[i].num = i;
    46     }
    47     cin >> m;
    48     for(int i=1; i<=m; i++){
    49         cin >> a[i+n].name >> a[i+n].num;
    50         a[i+n].num++;
    51     } 
    52     while(n1 < n+m) n1*=2;
    53     for(int i=1; i<=n1; i++) update(i, 1); 
    54     for(int i=n+m; i; i--){
    55         ans[find(a[i].num)]=a[i].name;
    56         update(find(a[i].num), -1);
    57     }
    58 //    for(int i=1; i<=n+m; i++) cout << ans[i] <<"
    "; 
    59     cin >> q;
    60 
    61     int ask;
    62     for(int i=1; i<=q; i++){
    63         cin >> ask;
    64         cout << ans[ask + 1] << "
    ";
    65     }    
    66     return 0;
    67 }
     

    最长上升子序列(树状数组):


    最长上升子序列(LIS):数值单调递增的长度

    状态表示:a[i] = max(a[j]<a[i]), 0<j<i{a[j]+1}

    边界:a[0] = -0x7fffffff

    目标:max{a[i]}, 1<i<N

    朴素算法(N2:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 int n;
     6 int a[100000], num[100000], ans=-0x7fffffff;
     7 int main(){
     8     freopen("LIS.in","r",stdin);
     9     ios::sync_with_stdio(false);
    10     cin >> n;
    11     for(int i=1; i<=n; i++) num[i] = 1;
    12     for(int i=1; i<=n; i++){
    13         cin >> a[i];
    14         int max=1;
    15         for(int j=1; j<i; j++){
    16             if(a[i] > a[j] && num[i]+1 > max)
    17                 max = num[i] + 1;
    18         }
    19         num[i] = max;
    20         if(max > ans) ans = max;
    21     }
    22     cout << ans <<"
    "; 
    23     return 0;
    24 }
     

    二分替换(NlogN):

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 int n, s, k, a[1000005];
     5 int find(int x){
     6     int l=1, r=s, mid;
     7     while(l <= r){
     8         mid = (l + r) >> 1;
     9         if(a[mid] < x) l = mid + 1;
    10         else r = mid - 1;
    11     }
    12     return l;
    13 }
    14 
    15 int main(){
    16     freopen("LIS.in","r",stdin);
    17     ios::sync_with_stdio(false);
    18     a[0]=-0x7fffffff;
    19     cin >> n;
    20     for(int i=1; i<=n; i++){
    21         cin >> k;
    22         if(a[s] < k) a[++s] = k;
    23         else{
    24             a[find(k)] = k;
    25         }
    26     }
    27     cout << s <<"
    ";
    28     return 0;
    29 } 
     

    Special Number(BFS):

    直接存余数用来计算就行了(想一想你平时算除法是怎么算的),顺便用string记答案,就不必找父结点了。

    题目名称

    Special Number

    主文件名

    number

    时间限制

    1s

    空间限制

    512M

    Special Number

    Problem Description

    The new year of 2012 has come. Jerry finds that 12 is a fun number: it’s the smallest integer that only consists of digit 0, 1 or 2, and is a multiple of 3. Similarly, it’s also the smallest integer that only consists of digit 0, 1 or 2, and is a multiple of 4.

    For a given positive integer n, Jerry wonders whether there exists a positive integer m that only consists of digit 0, 1 or 2, and is a multiple of n. If such numbers exist, the smallest one is called the special number for n.

    Input

    file:number.in

    The input has one line consisting of one positive integer n (1 ≤ n ≤ 10000000).

    Output

    file:number.out

    The output has just one line, containing the special number for n. Output −1 if the special number doesn’t exist.

    Input Sample

    15

    Output for Input Sample

    120

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<string>
     5 using namespace std;
     6 struct node{
     7     string ans;
     8     int num;
     9 }data[1000005];
    10 bool flag[1000005];
    11 int n, op=0, cl=2;
    12 
    13 int main(){
    14     freopen("number.in","r",stdin);
    15     ios::sync_with_stdio(false);
    16     cin >> n;
    17 //首结点入队
    18     data[1].ans = "1";
    19     data[1].num = 1;
    20     data[2].ans = "2";
    21     data[2].num = 2;
    22     while(op <= cl){
    23         op++;
    24         int num = data[op].num, num1;
    25         string name = data[op].ans;
    26         for(int i=0; i<=2; i++){
    27             num1 = num * 10 + i;
    28             num1 %= n;
    29             if(!flag[num1]){
    30                 cl++;
    31                 data[cl].num = num1;
    32                 data[cl].ans = name;
    33                 data[cl].ans += i + '0';
    34                 flag[num1] = 1;
    35                 if(num1 % n == 0){
    36                     cout << data[cl].ans << "
    ";
    37                     return 0;
    38                 }
    39             }
    40         }
    41     }
    42     cout << "-1" << "
    ";
    43     return 0;
    44 } 
     

    表达式求值:

    很锻炼编程能力的一道题,一定要在写程序之前设计好方案,免得把简单的事情弄得很复杂

    题目名称

    表达式

    主文件名

    expr

    时间限制

    1s

    空间限制

    512M

    表达式求值

    【题目描述】

    (expr.cpp/c/pas)

    给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。

    【输入文件】

    输入文件名:expr.in

    输入文件:输入仅有一行,为需要你计算的表达式,表达式中只包含数字、加法运算符“+”和乘法运算符“*”,且没有括号,所有参与运算的数字均为 0 到 2^31-1 之间的整数。输入数据保证这一行只有 0~ 9、+、*这 12 种字符。

    【输出文件】

    输出文件名:expr.out

    输出文件:输出只有一行,包含一个整数,表示这个表达式的值。注意:当答案长度多于 4位时, 请只输出最后位,前导 0 不输出。

    【样例输入1

    1+1*3+4

    【样例输出1

    8

    样例输入2

    1+1234567890*1

    样例输出2

    7891

    样例输入3】

    1+1000000003*1

    样例输出3

    4

    样例解释】

    样例 1 计算的结果为 8,直接输出 8。  

    样例 2 计算的结果为 1234567891,输出后4 位,即 7891。

    样例 3 计算的结果为 1000000004,输出后4 位,即 4。

    数据约定】全部输入为合法输入

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 char ch;
     6 int num, ans=0, ans1=1;
     7 
     8 int main(){
     9     freopen("expr.in", "r", stdin);
    10     ios::sync_with_stdio(false);
    11     
    12     while(~scanf("%c", &ch)){
    13         if(ch >= '0' && ch <= '9'){
    14             num = num * 10 + (ch - '0');
    15             num %= 10000; 
    16         }else if(ch == '*' || ch == '+'){
    17             ans1 *= num;
    18             if(ch == '+'){
    19                 ans += ans1;    
    20                 ans1 = 1;
    21             }
    22             num = 0;
    23         }
    24     }
    25     ans1 *= num;
    26     ans += ans1;
    27     
    28     cout << ans % 10000 << "
    ";
    29     return 0;
    30 }

     

    POJ2464(双树状数组):

    很复杂的一道题,需要想很久,也需要对树状数组熟练掌握

    Brownie Points II

    Time Limit: 5000MS

    Memory Limit: 65536K

    Total Submissions: 2921

    Accepted: 928

    Description

    Stan and Ollie play the game of Odd Brownie Points. Some brownie points are located in the plane, at integer coordinates. Stan plays first and places a vertical line in the plane. The line must go through a brownie point and may cross many (with the same x-coordinate). Then Ollie places a horizontal line that must cross a brownie point already crossed by the vertical line.
    Those lines divide the plane into four quadrants. The quadrant containing points with arbitrarily large positive coordinates is the top-right quadrant.

    The players score according to the number of brownie points in the quadrants. If a brownie point is crossed by a line, it doesn't count. Stan gets a point for each (uncrossed) brownie point in the top-right and bottom-left quadrants. Ollie gets a point for each (uncrossed) brownie point in the top-left and bottom-right quadrants.

    Stan and Ollie each try to maximize his own score. When Stan plays, he considers the responses, and chooses a line which maximizes his smallest-possible score.

    Input

    Input contains a number of test cases. The data of each test case appear on a sequence of input lines. The first line of each test case contains a positive odd integer 1 < n < 200000 which is the number of brownie points. Each of the following n lines contains two integers, the horizontal (x) and vertical (y) coordinates of a brownie point. No two brownie points occupy the same place. The input ends with a line containing 0 (instead of the n of a test).

    Output

    For each input test, print a line of output in the format shown below. The first number is the largest score which Stan can assure for himself. The remaining numbers are the possible (high) scores of Ollie, in increasing order.

    Sample Input

    11

    3 2

    3 3

    3 4

    3 6

    2 -2

    1 -3

    0 0

    -3 -3

    -3 -2

    -3 -4

    3 -7

    0

    Sample Output

    Stan: 7; Ollie: 2 3;

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 using namespace std;
     6 const int INF = 0x7fffffff;
     7 struct node{
     8     int x, y; 
     9     int stan;
    10 }a[200005];
    11 int n, minx=INF, miny=INF, maxx=-INF, maxy=-INF;
    12 int s[200005], ans[200005], num=1;
    13 
    14 int cmp(node a, node b){
    15     return a.y < b.y || (a.y == b.y && a.x > b.x);
    16 }
    17 
    18 int cmp2(node a, node b){
    19     return a.stan < b.stan;
    20 }
    21 
    22 int lowbit(int x){
    23     return x & -x;
    24 }
    25 int update(int x, int y){
    26     for(; x<=maxx; x+=lowbit(x))
    27         s[x] += y;
    28 } 
    29 int getsum(int x){
    30     int ans=0;
    31     for(; x; x-=lowbit(x))
    32         ans += s[x];
    33     return ans;
    34 }
    35 //反向更新查询:
    36 int update1(int x, int y){
    37     for(; x; x-=lowbit(x))
    38         s[x] += y;
    39 } 
    40 int getsum1(int x){
    41     int ans=0;
    42     for(; x<=maxx; x+=lowbit(x))
    43         ans += s[x];
    44     return ans;
    45 }
    46 
    47 int get(int x){
    48     int sum=0;
    49     for(int i=1; i<=n; i++){
    50         if(a[i].x < a[x].x && a[i].y > a[x].y)  
    51             sum++;
    52         if(a[i].x > a[x].x && a[i].y < a[x].y)  
    53             sum++;    
    54     }
    55     return sum;
    56 }
    57 
    58 int main(){
    59     freopen("POJ2464.in", "r", stdin);
    60     ios::sync_with_stdio(false);
    61     cin >> n;
    62     for(int i=1; i<=n; i++){
    63         cin >> a[i].x >> a[i].y;
    64         if(a[i].x < minx) minx = a[i].x;
    65         if(a[i].y < miny) miny = a[i].y; 
    66         if(a[i].x > maxx) maxx = a[i].x;
    67         if(a[i].y > maxy) maxy = a[i].y;
    68     }
    69     maxx -= minx+1; maxy -= miny+1;
    70     sort(a+1, a+n+1, cmp);
    71     for(int i=1; i<=n; i++){
    72         a[i].stan += getsum(a[i].x - minx + 1);
    73         update(a[i].x - minx + 1, 1);
    74     }
    75     
    76     memset(s, 0, sizeof s);
    77     for(int i=n; i; i--){
    78         a[i].stan += n - i - getsum(a[i].x - minx + 1);
    79         update(a[i].x - minx + 1, 1);
    80     }
    81     
    82     sort(a+1, a+n+1, cmp2);
    83     
    84     cout << "Stan :" << a[n].stan <<"; Ollie: ";
    85     for(int i=n; i; i--){
    86         if(a[i].stan != a[n].stan) break;
    87         ans[num++] = get(i);
    88     }
    89     
    90     sort(ans+1, ans+num);
    91     for(int i=1; i<num-1; i++) cout << ans[i] <<" ";
    92     cout << ans[num-1] <<";";
    93     return 0;
    94 }
     

    最后,整理一下树状数组记录空位的技巧,我们可以把一个数组a转化成记录逆序个数的数组b,再转化为a

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 int n, n1=1, a[100000], b[100000], s[100000];
     6 
     7 int lowbit(int x){
     8     return x & -x;
     9 }
    10 int update(int x, int y){
    11     for(; x<=n1; x+=lowbit(x))
    12         s[x] += y;
    13 }
    14 int getsum(int x){
    15     int ans=0;
    16     for(; x; x-=lowbit(x))
    17         ans += s[x];
    18     return ans;
    19 }
    20 
    21 int find(int x){
    22     int l=1, r=n1, mid;
    23     while(l < r-1){
    24         mid = (l+r) >> 1;
    25         if(s[mid] < x){
    26             x -= s[mid];
    27             l = mid + 1; 
    28         }else r = mid;
    29     }
    30     if(s[l] == x) return l;
    31     else return r;
    32 }
    33 
    34 int main(){
    35     freopen("a&b.in", "r", stdin);
    36     ios::sync_with_stdio(false);
    37     
    38     cin >> n;
    39     for(int i=1; i<=n; i++) cin >> a[i], a[i]++;
    40     while(n1 < n){
    41         n1 *= 2;
    42     }
    43     
    44     //a -> b
    45     for(int i=n; i; i--){
    46         b[i] = getsum(a[i]);
    47         update(a[i], 1);
    48     }
    49     for(int i=1; i<=n; i++) cout << b[i] <<" "; 
    50     cout << "
    ";
    51     
    52     //b -> a
    53     memset(s, 0, sizeof s);
    54     memset(a, 0, sizeof a);
    55     for(int i=1; i<=n1; i++) 
    56         update(i, 1); //记录空位个数 
    57     
    58     for(int i=1; i<=n; i++){
    59         a[i] = find(b[i] + 1);
    60         update(a[i], -1);
    61     }
    62     
    63     for(int i=1; i<=n; i++) cout << a[i] <<" ";
    64     return 0;
    65 } 
  • 相关阅读:
    Computer Browser服务自动停止
    Group By中Case分类统计
    C#判断网络状态
    Win7中VC6打开文件报错(转)
    SqlBulkCopy(大数据量拷贝)
    vc6开发ActiveX并发布全攻略(二)(转)
    VC6 Activex控件调试
    VC MessageBox
    常用基本AT指令
    WinForm自动重启
  • 原文地址:https://www.cnblogs.com/hnoi/p/10964464.html
Copyright © 2011-2022 走看看