• 2016 年宁波工程学院第七届ACM校赛题解报告


    2016 年宁波工程学院第七届ACM校赛题解报告


     

    本题解代码直接为比赛代码,仅供参考。

    A,B,C,D,G,H,J,K,L,M 来自 Ticsmtc 同学.

    F 来自 Gealo 同学.

    E,I 来自Alex 学长.


     

    Promblem A :    Two Sum

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述:

    给出n个数,另外给出⼀个整数S,判断是否可以从中取出2个数,使得这两个数的和是S。 

    输入:

    第⼀行有个整数T(1 <= T <= 10),代表数据组数。 对于每组数据,第⼀行包含两个整数n,S(2 <= n <= 103, 1 <= S <= 1000) 接下来⼀行包含n个整数,整数的⼤小在1到1000。 

    输出:

    对于每组数据,如果存在2个整数,和为S,则输出Yes,否则输出No。 

    样例输入:

    2

    5 6

    1 2 3 4 5

    5 10

    1 2 3 4 5

    样例输出:

    Yes

    No

    题解:

    题目意思不难理解,我们控制两重循环枚举一下是哪两个数,然后用加法判断下是不是S,如果是就可以,如果枚举完了所有的都没有发现能等于S的,那么就是不行。

    这里注意下,n个数,我们从下标零读入所有的数的话,那么外层循环i从0 ~ n- 1,考虑内层的时候,由于两个数不能够选重,所以内层循环 j 应当从 i + 1 ~ n - 1 ,然后看存储数字的save数组,save[i] + save[j] 是否等于 S 。

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <stack>
     4 #include <cstring>
     5 #include <algorithm>
     6 #include <string>
     7 using namespace std;
     8  
     9 int save[10000];
    10 int main(){
    11     int t;
    12     cin >> t;
    13     while(t--){
    14         int n;
    15         int S;
    16         cin >> n;
    17         cin >> S;
    18         for(int i = 0 ; i < n ; i++){
    19             cin >> save[i];
    20         }
    21         ///
    22         bool ok = 0;
    23         for(int i = 0 ; i < n - 1 ; i++){
    24             for(int j = i + 1 ; j < n ; j++){
    25                 if(save[i] + save[j] == S){
    26                     ok = 1; break;
    27                 }
    28             }
    29         }
    30         ////
    31         if(ok) cout << "Yes" << endl;
    32         else cout << "No" << endl;
    33          
    34     }
    35     return 0;
    36 }
    View Code

    Problem B : Poker

    时间限制: 1 Sec  内存限制: 128 MB

    题目描述:

    很多牌中都有顺子,今天⼩小编给您5张牌,需要客官您判断下这5张牌能不能连成⼀把同花顺。

    同花顺即花⾊一致的顺子,注意最⼩的顺子是A 2 3 4 5,最⼤的是10 J Q K A。 

    输入:

    第⼀行有⼀个整数T(1 <= T <= 30),代表数据组数。 每组数据包含5行,每⼀行包含牌的⾯值和花色

    ⾯值是{2 3 4 5 6 7 8 9 10 J Q K A}当中的一个, 花⾊是S(spade)、H(heart)、C(club)、D(diamond)其中之⼀。 

    输出:

    如果给定的牌可以组成同花顺,输出Yes;否则输出No。 

    样例输入:

    2

    5 H

    6 H

    7 H

    8 H

    9 H

    5 H

    6 H

    7 S

    8 C

    9 D

    样例输出:

    Yes

    No

    题解:

    先解决读入问题,很多同学尝试用两个char 读入前后一个牌号一个花色,那么当牌号是10的时候,char 只读入一个字符,就会出现错误,其次,如果用scanf 方式读取字符,需要很小心的考虑空格和回车符,这些都会被当作字符读入。所以十分麻烦。

    我采取的做法是读取字符串,然后转化回数字。

    好的,接下来我们用到一个手牌数组,save[] , 假如花色没有不同的,save数组中存储所有牌面的数字。

    这题的数字中的 A 比较特别, 既可以当作 1 看待 , 也可以当作 14 看待, 那么很有意思的事是当我们碰到A的时候转化成几。我选择了特判 A , 相当于把 1 和 14 都放进了手牌。

    我们对手牌save数组排序,从小到大,然后判断一下连续的五张牌是不是都是递增且相差一,如果有A的话,要判断两遍,因为有A,相当于手牌数组中有六个数,可能由1 ~ 5 个数(A为1)是一个顺子,也可能由2 ~ 6 个数(A为14)是一个顺子。

    然后就A掉了呐~。

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <stack>
     4 #include <cstring>
     5 #include <algorithm>
     6 #include <string>
     7 using namespace std;
     8  
     9 int save[100010];
    10  
    11 int trans(string &in){
    12     if(in.size() == 2){
    13         return 10;
    14     }
    15     char k = in[0];
    16     if(k >= '1' && k <= '9') return k - '0';
    17     if(k == 'J') return 11;
    18     if(k == 'Q') return 12;
    19     if(k == 'K') return 13;
    20 }
    21  
    22  
    23 int main(){
    24     int t;
    25     cin >> t;
    26     while(t--){
    27         char color = ' ';
    28         bool ok = 1;
    29         bool is_A = 0;
    30         int p = 0;
    31         for(int i = 0 ; i < 5 ; i++){
    32             //cout << i << endl;
    33             string temp; char c;
    34             cin >> temp >> c;
    35             //cout << temp << " " << c << endl;
    36             if(color == ' ') color = c;
    37             else if(color != c){
    38                 ok = 0;
    39             }
    40             ///
    41             if(temp == "A"){
    42                 save[p++] = 1;
    43                 save[p++] = 14;
    44                 is_A = 1;
    45             }
    46             else save[p++] = trans(temp);
    47         }
    48         if(!ok) {printf("No
    "); continue;}
    49         //
    50         sort(save,save + p);
    51         //
    52         int pre = save[0];
    53         for(int i = 1 ; i <= 4 ; i++){
    54             if(save[i] != pre + 1){
    55                 ok = 0; break;
    56             }
    57             pre = save[i];
    58         }
    59         //cout << "is A " << is_A << endl;
    60         if(is_A && !ok){
    61             ok = 1;
    62             pre = save[1];
    63             for(int i = 2 ; i <= 5 ; i++){
    64                 if(save[i] != pre + 1){
    65                     ok = 0; break;
    66                 }
    67                 pre = save[i];
    68             }
    69             //cout << "ok " << ok << endl;
    70         }
    71         ////
    72         if(!ok) printf("No
    ");
    73         else printf("Yes
    ");
    74     }
    75     return 0;
    76 }
    View Code

    Problem C: I Need Minmum Number

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述:

    你有⼀个序列,一开始是空的,接下来执行n次操作,每次操作都是以下3种之⼀

     2 value 表示在序列末尾加⼊一个新的数

     1 表⽰删除序列末尾的那个数(此次操作在序列为空时不会出现)

     0 表⽰示询问当前序列⾥的最小值(此次操作在序列为空时不会出现) 

    输入:

    第⼀行有个整数T(1 <= T <= 10),代表数据组数。 对于每组数据,第⼀行包含⼀个整数n(1 <= n <= 105) 接下来包含n⾏,代表n次操作。 如果是一个整数0,代表询问当前序列⾥的最小值。 如果是一个整数1,代表删除序列末尾的那个数。

    否则就是2 value,代表在序列末尾加入value(-10000 <= value <= 10000)。 

    输出:

    对于每个0操作,输出当前序列里的最小值。 

    样例输入:

    1

    5

    2 3

    2 1

    0

    2 -1

    0

    样例输出:

    1

    -1

    题解:

    想用一个栈,和一个变量存储最小值,插入一个数就比较一下,询问的时候直接输出这个存储最小值变量,这样的同学太天真了。

    问题是,还有弹出的操作,万一栈顶是最小值,你弹出了栈顶,然后你记录最小值的这个东西又要更新(你从哪里更新呢)。。。。

    很多种做法,我的做法是设置两个数组,save数组模拟栈操作,minlist数组也是一个栈,纪录save栈中连续不增的子序列。那么得到以下规则:

    1.插入一个数val时,val插入save栈末尾。如果val比minlist栈顶元素小或等于栈顶元素,那么将val插入minlist栈,如果val比minlist栈顶元素大,则不操作。说明save栈在插入val前还有比val小的数。

    2.删除save栈顶的数时,首先删除这个栈顶数,其次比较下,这个栈顶数val,是不是等于minlist栈顶数,如果相等,同样将minlist栈顶删除。如果不等于,那么不做操作。

    3.请求save栈中最小元素时,即为minlist的栈顶元素。

    然后就A掉了呐~。

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <stack>
     4 #include <cstring>
     5 using namespace std;
     6  
     7 int save[100010];
     8 int minlist[100010];
     9  
    10 int main(){
    11     int t;
    12     scanf("%d",&t);
    13     while(t--){
    14         int k;
    15         scanf("%d",&k);
    16         //
    17         int pos = 0;
    18         int minpos = 0;
    19         //
    20         for(int i = 0 ; i < k ; i++){
    21             int op;
    22             scanf("%d",&op);
    23             if(op == 2){
    24                 int val;
    25                 scanf("%d",&val);
    26                 save[pos++] = val;
    27                 ///
    28                 if(minpos == 0){
    29                     minlist[minpos++] = val;
    30                 }
    31                 else if(val <= minlist[minpos - 1]){
    32                     minlist[minpos++] = val;
    33                 }
    34             }
    35             else if(op == 1){
    36                 int temp = save[pos - 1];
    37                 pos--;
    38                 ////////
    39                 if(temp == minlist[minpos - 1]){
    40                     minpos--;
    41                 }
    42             }
    43             else{
    44                 printf("%d
    ",minlist[minpos - 1]);
    45             }
    46         }
    47     }
    48     return 0;
    49 }
    View Code

    Problem D : Two’s Complement

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述:

    现代大部分计算机都采用补码的形式存储有符号数,一个长度为w的补码b,

    对应的十进制数字为:

    其中bi要么为1,要么为0。

    例如,采用5位来表示时,-1的补码就是11111,现在告诉你一串补码,求出对应

    的十进制下的数字。

    输入:

    第一行有一个整数T,代表数据组数(T <= 1000)。

    每组数据输入只有一行,代表补码(长度小于等于30,大于等于1)。

    输出:

    对于每组数据,输出该补码对应的十进制数。

    样例输入:

    3

    1001

    10

    001

    样例输出:

    -7

    -2

    1

    题解:

    嗯,其实这题需要知道二进制表示的一些知识,一个二进制数,我们从右到左叫做从低位到高位,那么我们从低位到高位的权值依次从2^0 , 2^1 , 2^2 ….. 

    比如,二进制数 101

    如何得到十进制数呢 , 从低位到高位,三位的权值分别为 2^0 , 2^1 , 2^2. 

    那么他的十进制就是1 * 2^0 + 0 * 2^1 + 1 * 2^2.

    好了,明白了低位高位和权值的概念,这题就已经可以做了。

    这个数学公式的意思是:

    -1  * 最高位上的数字 * 最高位上的权值 +(除去最高位后,次高位到最低位表示的这个二进制数。)

    比如11111(5个1)是-1,是如何得到的呢?

    首先我们发现最高位(也就是最左位)是1,权值是2^4,那么根据公式前一部分 , 计算出为-16.

    除去了最高位剩下了1111(四个1)按照二进制计算为15。

    那么两部分加起来就是-1啦。

    读进来的时候用字符串,然后自己操作下权值就好?

    A掉了哇~

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <stack>
     4 #include <cstring>
     5 using namespace std;
     6 char save[100010];
     7 int main(){
     8     int t;
     9     scanf("%d",&t);
    10     while(t--){
    11         scanf("%s",save);
    12         int len = strlen(save);
    13         int ans = 0;
    14         long long quan = 1;
    15         for(int i = len - 1; i >= 1 ; i--){
    16             ans += (quan * (save[i] - '0'));
    17             quan*=2;
    18         }
    19         ans = ans + (-1) * (save[0] - '0') * quan;
    20         cout << ans << endl;
    21     }
    22     return 0;
    23 }
    View Code

    Problem E : Just Go

    时间限制: 3 Sec  内存限制: 64 MB

    题目描述:

    There is a river, which contains n stones from left to right. These stones are magic, each

    one has a magic number Ai which means if you stand on the ith stone, you can jump to (i +1)th stone, (i+2)th stone, ..., (i+Ai)th stone(when i+Ai > n, you can only reach as far as n), you want to calculate the number of ways to reach the nth stone.

    Notice: you can not jump from right to left! 

    输入:

    Input starts with an integer T(1 <= T <= 10), denoting the number of test cases. Each test case contains an integer n(1 <= n <= 105), denoting the number stones. Next line contains n integers Ai(1 <= Ai <= 108). 

    输出:

    For each test case, print the number of way to reach the nth stone module 109+7. 

    样例输入:

    3

    5

    1 2 3 4 5

    1

    10

    2

    2 1

    样例输出:

    3

    1

    1

    题解:

    按照题目意思,模拟操作,套数据结构线段树。

    代码:

      1 #include <stdio.h>
      2 #include <algorithm>
      3 #include <math.h>
      4 using namespace std;
      5 
      6 const int N = 110010;
      7 const int mod = 1e9 + 7;
      8 
      9 struct SegTree {
     10     int l, r;
     11     int way;
     12     int add;
     13 }tree[N << 2];
     14 
     15 void modify(int &target, int val) {
     16     target += val;
     17     target = (target % mod + mod) % mod;
     18 }
     19 
     20 void pushup(int p) {
     21     modify(tree[p].way, (tree[p << 1].way + tree[p << 1 | 1].way) % mod);
     22 }
     23 
     24 void build(int p, int l, int r) {
     25     tree[p].l = l;
     26     tree[p].r = r;
     27     tree[p].add = tree[p].way = 0;
     28     if (l == r) {
     29         if (l == 1) {
     30             tree[p].way = 1;
     31         }
     32         return;
     33     }
     34     int mid = (l + r) >> 1;
     35     build(p << 1, l, mid);
     36     build(p << 1 | 1, mid + 1, r);
     37     pushup(p);
     38 }
     39 
     40 void pushdown(int p) {
     41     if (tree[p].add) {
     42         modify(tree[p << 1].add, tree[p].add);
     43         modify(tree[p << 1 | 1].add, tree[p].add);
     44         modify(tree[p << 1].way, tree[p].add);
     45         modify(tree[p << 1 | 1].way, tree[p].add);
     46         tree[p].add = 0;
     47     }
     48 }
     49 
     50 void update(int p, int l, int r, int val) {
     51     if (l <= tree[p].l && tree[p].r <= r) {
     52         modify(tree[p].add, val);
     53         modify(tree[p].way, val);
     54         return;
     55     }
     56     pushdown(p);
     57     int mid = (tree[p].l + tree[p].r) >> 1;
     58     if (r <= mid) {
     59         update(p << 1, l, r, val);
     60     }
     61     else if (l > mid) {
     62         update(p << 1 | 1, l, r, val);
     63     }
     64     else {
     65         update(p << 1, l, mid, val);
     66         update(p << 1 | 1, mid + 1, r, val);
     67     }
     68     pushup(p);
     69 }
     70 
     71 int query(int p, int pos) {
     72     if (tree[p].l == tree[p].r) {
     73         return tree[p].way;
     74     }
     75     pushdown(p);
     76     int mid = (tree[p].l + tree[p].r) >> 1;
     77     if (pos <= mid) {
     78         return query(p << 1, pos);
     79     }
     80     else {
     81         return query(p << 1 | 1, pos);
     82     }
     83 }
     84 
     85 int main() {
     86     int t;
     87     scanf("%d", &t);
     88     while (t--) {
     89         int n;
     90         scanf("%d", &n);
     91         int val;
     92         build(1, 1, n);
     93         for (int i = 1; i <= n; ++i) {
     94             scanf("%d", &val);
     95             int way = query(1, i);
     96             int s = i + 1;
     97             int e = min(n, i + val);
     98             if (i == n) {
     99                 continue;
    100             }
    101             update(1, s, e, way);
    102         }
    103         printf("%d
    ", query(1, n));
    104     }
    105     return 0;
    106 }
    View Code

    Problem F : Fat Brother’s new way

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述:

    I bet, except Fat Brothers, all of you don’t like strange way to show integers , he is really like this way to showing integers:

    1 -> ‘A’

    2 -> ‘B’

    …….

    26 -> ‘Z’

    27 -> ‘AA’

    28 -> ‘AB’

    …….

    Unfortunately, Fat Brother’s mathematics is poor, so he needs your help, he will give you some integers, and you must transform it with Fat Brother’s way.

    输入:

    Input starts with an integer T(T <= 10000), denoting the number of test case.

    For each test case, an integers n(1 <= n <= 2147483647) is given.

    输出:

    For each case,  output the corresponding string with upper-case letters.

    样例输入:

    3

    17311

    2068

    37

    样例输出:

    YOU

    CAN

    AK

    题解:

    先将26个字母存入0~25的数组中,第一步将n - 1对26取余,余数便是对应的字母所在的位置,接下来便是将n除以26直到0为止反复进行这一系列的操作。还有一些细节值得注意。

    当n为52时,答案是AZ但只是按这种方法输出会是BZ由于52/26=2。所以在每次n%26=0时n/26

    时要减一

    代码:

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 using namespace std;
     5 char a[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     6 char b[100000];
     7 int main()
     8 {
     9     int t;
    10     scanf("%d" , &t);
    11     int n;
    12     for(int i = 0 ; i < t ; i++)
    13     {
    14         scanf("%d" , &n);
    15         int g = 0;
    16         while(n > 0)
    17         {
    18             if(n % 26 != 0)
    19                 b[g++] = a[n % 26 - 1];
    20             else
    21             {
    22                 b[g++] = a[25];
    23                 n--;
    24             }
    25             if(n == 26)
    26                 break;
    27             n /= 26;
    28         }
    29         for(int i = g - 1 ; i >= 0 ; i--)
    30             printf("%c" , b[i]);
    31         printf("
    ");
    32     }
    33     return 0;
    34 }
    View Code

    Problem G : Is The Same?

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述:

    给出2个字符串S和T,如果可以通过循环移位使得S和T相等,则我们称S和T是同构字符串, 例如S=“abcd”, T=“bcda”,则S和T是同构字符串;而S=“abcd”和T=“bcad”则不是同构字符串。

    循环移位是指:在⼀个长度为n的字符串S中,取⼀个任意下标i,把字符串分为两段,分别为 S1S2...Si 和Si+1Si+2...Sn,然后把字符串变为Si+1Si+2...SnS1S2...Si,例如S=“qwerty”,取i=3, 则变 为”rtyqwe”(注意,一个字符串本⾝身也算是它的同构字符串)。 

    输入:

    第⼀行包含一个整数T(1 <= T <= 20),代表测试组数。

    对于每组数据,包含2个字符串,字符串长度都小于等于105且非空,输入保证字符串只包含小写字⺟。 

    输出:

    对于每组数据,如果这两个字符串是同构字符串,则输出Yes,否则输出No。 

    样例输入:

    2

    abcd

    bcda

    abcd

    bcad

    样例输出:

    Yes

    No

    题解:

    姑且算有点算法的水题吧,我们把第一个串叫做A串,第二个叫做B串,如果A串长度和B串都不一样,那么肯定不同构。

    那么A串和B串长度相等时,我们继续。

    好像有很多的思路,我的想法是将A串倍增两倍,比如A串是abcde,我倍增后A串为abcdeabcde,然后在倍增后的A串中找一下有没有B串就行了。找的到就是同构,找不到就不同构。

    字符串匹配,套个KMP就稳稳的过掉了~

    A掉了呐~

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <stack>
     4 #include <cstring>
     5 using namespace std;
     6 char A[300010];
     7 char B[300010];
     8 int Next[300010];
     9  
    10 void check(){
    11     int len = strlen(B);
    12     for(int i = 0; i < len ; i++){
    13         cout << Next[i] << " ";
    14     }
    15     cout << endl;
    16     return ;
    17 }
    18  
    19 void make_next(){
    20     Next[0] = -1;
    21     int len = strlen(B);
    22     int i = 0, k = -1;
    23     while(i < len){
    24         if(k == -1 || B[i] == B[k]){
    25             Next[++i] = ++k;
    26         }
    27         else k = Next[k];
    28     }
    29     return ;
    30 }
    31  
    32 bool kmp(){
    33     make_next();
    34     int len1 = strlen(A);
    35     int len2 = strlen(B);
    36     ////
    37     int i = 0 , k = 0;
    38     while(i < len1 && k < len2){
    39         if(k == -1 || A[i] == B[k]){i++; k++;}
    40         else k = Next[k];
    41     }
    42     if(k == len2) return 1;
    43     else return 0;
    44 }
    45  
    46 int main(){
    47     int t;
    48     scanf("%d",&t);
    49     while(t--){
    50         scanf("%s",A);
    51         scanf("%s",B);
    52         int len = strlen(A);
    53         //
    54         if(len != strlen(B)) {printf("No
    "); continue;}
    55         //
    56         for(int i = 0 ; i < len ; i++){
    57             A[len + i] = A[i];
    58         }
    59         A[2 * len - 1] = '';
    60          
    61         bool ans = kmp();
    62          
    63         if(ans) printf("Yes
    ");
    64         else printf("No
    ");
    65     }
    66     return 0;
    67 }
    View Code

    Problem H : Party

    时间限制: 2 Sec  内存限制: 64 MB

    题目描述:

    N students were invited to attend a party, every student has some friends, only if someone’s all friends attend this party, this one can attend the party(ofcourse if he/she has no friends, he/she also can attend it.), now i give the friendship between these students, you need to tell me whether all of them can attend the party.

    Note that the friendship is not mature, for instance, if a is b’s friend, but b is not necessary a’s friend. 

    输入:

    Input starts with an integer T(1 <= T <= 10), denoting the number of test case.

    For each test case, first line contains an integer N(1 <= N <= 100000), denoting the number of students.

    Next n lines, each lines first contains an integer K, denoting the number of friends belong to student i(indexed from 1). Then following K integers, denoting the K friends.

    You can assume that the number of friendship is no more than 100000, and the relation like student A is himself’s friend will not be existed. 

    输出:

    For each test case, if all of the students can attend the party, print Yes, otherwise print No. 

    样例输入:

    2

    3

    1 2

    1 3

    1 1

    3

    1 2

    0

    1 1

    样例输出:

    No

    Yes

    题解:

    题目大意就是要邀请一堆人去玩,然后呢,有些人要某些人去才肯去,有些人呢,自己就会去。

    题目给你N个人,告诉你依赖的关系,或者说这个人不依赖他人。问你能否所有的人都要到。

    作为一个有向图,所有人都能到的条件应该就是不存在环,那么首先想到的是简单的用dfs判一下环,可是这里人数太多,用dfs能跑到明年,而且万一不是全部联通的,跑都跑不清楚了。所以改变思路。

    先进行规定,如果A依赖B,我们说A到B有一条边(有向边A—>B)。

    接下来:

    1.建立这个有向图。

    2.寻找出度为0的点,放进队列Q中。

    3. while(Q不为空)

        {

        取出队列中的第一个点,删去这个点的相邻边。并将这个点删除。

        如果发现删除这个点相邻边后,有点的出度为0,则将这个点压入队列尾。

        }

    4.若没有点剩余,则全部能去,反之不行。

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <vector>
     5 #include <queue>
     6 
     7 using namespace std;
     8 
     9 const int MAX = 100010;
    10 
    11 vector<int> edge[MAX];
    12 queue<int> Q;
    13 int out[MAX];
    14 
    15 void init(int n){
    16     for(int i = 1 ; i <= n ; i++){
    17         edge[i].clear();
    18     }
    19     return;
    20 }
    21 
    22 int main(){
    23     
    24     int t;
    25     scanf("%d",&t);
    26     
    27     while(t--){
    28         int N;
    29         scanf("%d",&N);
    30         int all = N;
    31         while(!Q.empty()) Q.pop();
    32         init(N);
    33         //////////////////////
    34         for(int i = 1 ; i <= N ; i++){
    35             int k;
    36             scanf("%d",&k);
    37             out[i] = k;
    38             if(!k) Q.push(i);
    39             for(int j = 0 ; j < k ; j++){
    40                 int temp;
    41                 scanf("%d",&temp);
    42                 edge[temp].push_back(i);
    43             }
    44         }
    45         //////////////////////
    46         
    47         while(!Q.empty()){
    48             int now  = Q.front();
    49             Q.pop();
    50             all--;
    51             ///////
    52             int size = edge[now].size();
    53             for(int i = 0;  i < size ; i++){
    54                 int op = edge[now][i];
    55                 out[op]--;
    56                 if(out[op] == 0) Q.push(op);
    57             }
    58         }
    59         
    60         ///////////
    61         if(all) printf("No
    ");
    62         else printf("Yes
    ");
    63         
    64     }
    65     
    66     return 0;
    67 }
    View Code

    Problem I :  Alex’s Foolish Function

    时间限制: 8 Sec  内存限制: 128 MB

    题目描述:

    Alex has an array F which size is n, initially each element’s value is zero. Now he wants to operate the array, he has 4 different functions:

    1) Function A(l, r):

    Add the elements between l to r (inclusive) where the ith add i - l + 1, for instance, if l is 4,

    r is 6 and the elements between 4 to 6 is 3 4 10, after this operation, these elements will become 4 6 13.

    2) Function B(l, r):

    Add the elements between l to r (inclusive) where the ith add r - i + 1, for instance, if l is 4,

    r is 6 and the elements between 4 to 6 is 3 4 10, after this operation, these elements will become 6 6 11.

    3) Function C(l, r, x):

    Set all the elements(between l to r) to x, for instance, if l is 4, r is 6 and the elements

    between 4 to 6 is 3 4 10, and x = 2, after this operation, these elements will become 2 2 2.

    4) Function S(l, r):

    Output Fl + Fl+1 + Fl+2 + ...+ Fr. 

    输入:

    Input start with an integer T(1 <= T <= 5), denoting the number of test case.

    For each test case, first line contains n, m (1 <= n <= 200000, 1 <= m <= 100000), denoting the array’size and the number of operations.

    Next m lines, each line contains an operation, formatting as

    A l r

    B l r

    C l r x

    S l r 

    输出:

    For each S Function operations, output the sum. 

    样例输入:

    1

    5 4

    A 1 3

    B 2 5

    C 1 1 2

    S 1 5

    样例输出:

    17

    题解:

    按照提议模拟操作,但是要套数据结构,线段树。

    代码:

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 const double pi = acos(-1.0);
      5 const int inf = 0x3f3f3f3f;
      6 const double eps = 1e-15;
      7 typedef long long LL;
      8 typedef unsigned long long ULL;
      9 typedef pair <int, int> PLL;
     10 const LL INF = (1LL << 60);
     11 
     12 const int N = 250010;
     13 struct SegTree {
     14     int l, r;
     15     LL add1, add2, add3; //add1 -> 覆盖, add2->加某个值, add3->加减下标
     16     LL sum;
     17 }tree[N << 2];
     18 
     19 void pushup(int p) {
     20     tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
     21 }
     22 
     23 void pushdown(int p) {
     24     if (tree[p].add1 != -inf) {
     25         tree[p << 1].add2 = tree[p << 1].add3 = tree[p << 1 | 1].add2 = tree[p << 1 | 1].add3 = 0;
     26         tree[p << 1].add1 = tree[p << 1 | 1].add1 = tree[p].add1;
     27         tree[p << 1].sum = tree[p].add1 * (tree[p << 1].r - tree[p << 1].l + 1);
     28         tree[p << 1 | 1].sum = tree[p].add1 * (tree[p << 1 | 1].r - tree[p << 1 | 1].l + 1);
     29         tree[p].add1 = -inf;
     30     }
     31     if (tree[p].add2) {
     32         tree[p << 1].add2 += tree[p].add2;
     33         tree[p << 1 | 1].add2 += tree[p].add2;
     34         tree[p << 1].sum += tree[p].add2 * (tree[p << 1].r - tree[p << 1].l + 1);
     35         tree[p << 1 | 1].sum += tree[p].add2 * (tree[p << 1 | 1].r - tree[p << 1 | 1].l + 1);
     36         tree[p].add2 = 0;
     37     }
     38     if (tree[p].add3) {
     39         tree[p << 1].add3 += tree[p].add3;
     40         tree[p << 1 | 1].add3 += tree[p].add3;
     41         tree[p << 1].sum += tree[p].add3 * (LL)(tree[p << 1].r - tree[p << 1].l + 1) * (tree[p << 1].l + tree[p << 1].r) / 2;
     42         tree[p << 1 | 1].sum += tree[p].add3 * (LL)(tree[p << 1 | 1].r - tree[p << 1 | 1].l + 1) * (tree[p << 1 | 1].l + tree[p << 1 | 1].r) / 2;
     43         tree[p].add3 = 0;
     44     }
     45 }
     46 
     47 void build(int p, int l, int r) {
     48     tree[p].l = l;
     49     tree[p].r = r;
     50     tree[p].sum = tree[p].add2 = tree[p].add3 = 0;
     51     tree[p].add1 = -inf;
     52     if (l == r) {
     53         return;
     54     }
     55     int mid = (l + r) >> 1;
     56     build(p << 1, l, mid);
     57     build(p << 1 | 1, mid + 1, r);
     58 }
     59 
     60 void update(int p, int l, int r, int id, int val) {
     61     if (l <= tree[p].l && tree[p].r <= r) {
     62         if (id == 1) {
     63             tree[p].add1 = (LL)val;
     64             tree[p].add2 = tree[p].add3 = 0;
     65             tree[p].sum = (LL)val * (tree[p].r - tree[p].l + 1);
     66         }
     67         else if (id == 2) {
     68             tree[p].add2 += (LL)val;
     69             tree[p].sum += (LL)val * (tree[p].r - tree[p].l + 1);
     70         }
     71         else {
     72             tree[p].add3 += (LL)val;
     73             tree[p].sum += (LL)val * (LL)(tree[p].r - tree[p].l + 1) * (LL)(tree[p].l + tree[p].r) / 2;
     74         }
     75         return;
     76     }
     77     pushdown(p);
     78     int mid = (tree[p].l + tree[p].r) >> 1;
     79     if (r <= mid) {
     80         update(p << 1, l, r, id, val);
     81     }
     82     else if (l > mid) {
     83         update(p << 1 | 1, l, r, id, val);
     84     }
     85     else {
     86         update(p << 1, l, mid, id, val);
     87         update(p << 1 | 1, mid + 1, r, id, val);
     88     }
     89     pushup(p);
     90     //printf("区间[%d, %d], sum = %lld
    ", tree[p].l, tree[p].r, tree[p].sum);
     91 }
     92 
     93 LL query(int p, int l, int r) {
     94     if (l <= tree[p].l && tree[p].r <= r) {
     95         return tree[p].sum;
     96     }
     97     pushdown(p);
     98     int mid = (tree[p].l + tree[p].r) >> 1;
     99     if (r <= mid) {
    100         return query(p << 1, l, r);
    101     }
    102     else if (l > mid) {
    103         return query(p << 1 | 1, l, r);
    104     }
    105     else {
    106         return query(p << 1, l, mid) + query(p << 1 | 1, mid + 1, r);
    107     }
    108 }
    109 
    110 int main() {
    111     int t;
    112     scanf("%d", &t);
    113     while (t--) {
    114         int n, m, l, r, val;
    115         char str[3];
    116         scanf("%d%d", &n, &m);
    117         build(1, 1, n);
    118         while (m--) {
    119             scanf("%s", str);
    120             if (str[0] == 'S') {
    121                 scanf("%d%d", &l, &r);
    122                 printf("%lld
    ", query(1, l, r));
    123             }
    124             else if (str[0] == 'A') {
    125                 scanf("%d%d", &l, &r);
    126                 update(1, l, r, 2, 1 - l);
    127                 update(1, l, r, 3, 1);
    128             }
    129             else if (str[0] == 'B') {
    130                 scanf("%d%d", &l, &r);
    131                 update(1, l, r, 2, r + 1);
    132                 update(1, l, r, 3, -1);
    133             }
    134             else {
    135                 scanf("%d%d%d", &l, &r, &val);
    136                 update(1, l, r, 1, val);
    137             }
    138         }
    139     }
    140     return 0;
    141 }
    View Code

    Problem J : 对数问题

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述:

    Alex有一个问题,给你一个数组,然后给你一个数k,问你数组中和为k的数对有多少对(各个对中下标不同就算一对)。

    输入:

    有t(t <= 10)组数,每组给你数n(n <= 100)和k(k <= 10000),表示数组的大小,然后下面给你n个数ai(1 <= ai <= 100)表示数组的元素大小。

    输出:

    输出和为k的对数有多少对,没有的话为0。

    样例输入:

    1

    4 3

    1 2 1 2

    样例输出:

    4

    题解:

    和对数一点关系都没有,是“数对问题”比较贴切吧。

    还是很水的,全部试一遍就好了,两个for,有点像A题,只是这题要你数出几个,不要数重复就好。

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <stack>
     4 #include <cstring>
     5 #include <algorithm>
     6 #include <string>
     7 using namespace std;
     8  
     9 long long  save[10010];
    10 int main(){
    11     int t;
    12     cin >> t;
    13     while(t--){
    14         int n;
    15         int K;
    16         cin >> n;
    17         cin >> K;
    18         for(int i = 1; i <= n ; i++){
    19             cin >> save[i];
    20         }
    21         for(int i = 1 ; i <= n; i++){
    22             sum[i] = save[i] + sum[i - 1];
    23         }
    24         int ans = 0;
    25         for(int i = 1 ; i <= n; i++){
    26             for(int j = i + 1 ; j <= n ; j++){
    27                 if(save[i] + save[j] == K) ans++;
    28             }
    29         }
    30         ///
    31         cout << ans << endl;
    32     }
    33     return 0;
    34 }
    View Code

    Problem K : Page Fault

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述:

    要说起操作系统存储器管理,少不了要谈下分页存储管理,它把进程的虚拟地址空间和实际

    的主存地址空间划分为同样⼤小的页(1KB,2KB或者4KB),然后提供一种从虚拟地址到实际物理地址的翻译机制。另外,虚拟地址空间还把一些表⽰完整信息的⻚划分为一个段,且每个段都有⼀个权限要求。

    如果一个虚拟地址⽆法找到对应的实际物理地址,CPU就会引发一个缺⻚中断,但是在这之 前,CPU必须知道这个地址是否合法,简单来说,CPU会把这个地址和虚拟地址空间的各个段⽐较,如果地址没有落在这些段⾥,或者虽然在一个段中,但是权限不够,就会产⽣一个Segment Fault 异常;否则说明这是一个合法地址,可以进⾏页面调度。 

    输入:

    第⼀行有⼀个整数T,代表数据组数(T <= 1000)。 每组数据包含一个整数n(1 <= n <= 100),代表段的数目。 接下来n行,包含三个整数 start, end, prot,start是开始地址, end是结束地址,prot是对应权限,保证段与段之间不相交 (即不会出现诸如[3,5], [5,7]之类的情况)。 最后⼀行包含一个整数address,表⽰示需要验证的地址。

    (0 <= start, end, address <= 231 - 1, 0 <= prot <= 1) 假设我们的程序对prot为1的段没有权限,所以无法访问这些段。

    输出:

    对于每组数据,如果产⽣生了段错误,输出Segment Fault,否则输出Missing Page Interrupt。 

    样例输入:

    3

    3

    0 3 1

    4 5 0

    6 8 1

    7

    1

    0 3 1

    2

    0 0 0

    1 3 0

    2

    样例输出:

    Segment Fault

    Segment Fault

    Missing Page Interrupt

    题解:

    用结构体纪录每一个给你的区间的上下段,和记录这个区间的权限,设置成数组,读入所有的段,然后for一遍就可以了,水题。

    特别注意一下,假如给你的段最大到达 比如是 8 , 他给你地址是 10 的时候,输出也是 fault.

    我用了long long,貌似是不需要的,用int存就可以了。

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <stack>
     4 #include <cstring>
     5 #include <algorithm>
     6 #include <string>
     7 using namespace std;
     8  
     9 pair<long long , long long> save[100010];
    10 bool pro[10100];
    11  
    12 int main(){
    13     int t;
    14     cin >> t;
    15     while(t--){
    16         int n;
    17         scanf("%d",&n);
    18         for(int i = 0; i < n ; i++){
    19             long long temp1 , temp2 , p;
    20             cin >> temp1 >> temp2 >> p;
    21             save[i] = make_pair(temp1,temp2);
    22             if(p == 1) pro[i] = 1;
    23             else pro[i] = 0;
    24         } 
    25         long long add;
    26         cin >> add;
    27         bool ok = 0;
    28         for(int i = 0; i < n ; i++){
    29             long long begin = save[i].first;
    30             long long end = save[i].second;
    31             ////
    32             if(add >= begin && add <= save[i].second){
    33                 if(pro[i] == 1) ok = 0;
    34                 else ok = 1;
    35                 break;
    36             }
    37         }
    38         ///
    39         if(!ok) cout << "Segment Fault" << endl;
    40         else cout << "Missing Page Interrupt" << endl;
    41     }
    42     return 0;
    43 }
    View Code

    Problem L : VectorMultiply

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述:

    There are two vector A(x1, x2, x3, ..., xn) and B(y1, y2, ..., yn), and the dot product(点积) is x1*y1 + x2*y2 + ... + xn*yn.

    You can swap the order of any dimension, for example, A = {1, 2, 3}, then you can make A to {1, 3, 2} or {2, 1, 3} and so on.

    Now you need to calculate the maximum value of dot product.

    输入:

    Input starts with an integer T (T <= 20)denoting the test case.

    For each test case, first line contains n(n <= 10000)

    then two lines follow, each line contains n integers(1 <= xi, yi <= 100000).

    输出:

    For each test case, print the maximum value of dot product.

    样例输入:

    1

    4

    1 3 2 10

    2 3 4 1

    样例输出:

    54

    题解: 

    这两个向量里面的数字都是正数,那么就很简单了,大的乘大的,小的乘小的就好。用sort排序啊,自己写个冒泡的话,实在效率太低了.......

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <stack>
     4 #include <cstring>
     5 #include <algorithm>
     6 #include <string>
     7 using namespace std;
     8  
     9 long long  save1[10010];
    10 long long  save2[10010];
    11 int main(){
    12     int t;
    13     cin >> t;
    14     while(t--){
    15         long long ans = 0;
    16         int n;
    17         cin >> n;
    18         for(int i = 0 ; i < n ; i++){
    19             cin >> save1[i];
    20         }
    21         for(int i = 0 ; i < n ; i++){
    22             cin >> save2[i];
    23         }
    24         sort(save1,save1+n);
    25         sort(save2,save2+n);
    26         for(int i = 0 ; i < n ; i++){
    27             ans += (save1[i] * save2[i]);
    28         }   
    29         cout << ans << endl;
    30     }
    31     return 0;
    32 }
    View Code

    Problem M : Hot Hot Up

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述:

    欢迎参加本次比赛,请输出谚语: “A young idler, an old beggar”。 

    输入:

    本题没有输⼊。 

    输出:

    输出”A young idler, an old beggar”(不含引号)。 

    样例输出:

    A young idler, an old beggar

    题解:

    作为本场比赛最难的一道题,我真不知道这题题解怎么写。

    代码:

    1 #include <iostream>
    2 #include <cstdio>
    3 using namespace std;
    4 int main(){
    5     printf("A young idler, an old beggar
    ");
    6     return 0;
    7 }
    8  
    View Code
  • 相关阅读:
    二分图 洛谷P2055 [ZJOI2009]假期的宿舍
    并查集 洛谷P1640 [SCOI2010]连续攻击游戏
    贪心 洛谷P2870 Best Cow Line, Gold
    贪心 NOIP2013 积木大赛
    快速幂 NOIP2013 转圈游戏
    倍增LCA NOIP2013 货车运输
    树形DP 洛谷P2014 选课
    KMP UVA1328 Period
    动态规划入门 BZOJ 1270 雷涛的小猫
    KMP POJ 2752Seek the Name, Seek the Fame
  • 原文地址:https://www.cnblogs.com/ticsmtc/p/5478434.html
Copyright © 2020-2023  润新知