• 训练赛Day7


    训练赛Day7 - The 36th ACM/ICPC Asia Regional Dalian Site —— Onsite Contest

    D - Hexadecimal View

    题目大意

    十六进制对计算机程序员非常重要和有用。您被要求提供给定数据的十六进制视图。十六进制视图由一行或多行组成。除最后一行之外的每一行代表16个字符。每行由三个以空格分隔的列组成:

    • addr:此行的4位十六进制起始地址。
    • dump:此行的十六进制表示形式,用空格分隔每两个字符。如果最后一行中少于16个字符,请用空格填充它。
    • text:此行的ASCII转换,大写字符转换为小写和小写字符转换为大写。

    使用小写字母数字。有关详细信息,请参阅示例。

    数据范围

    有多个测试用例。每行都是一个测试用例。该行由不少于1个且不超过4096个可打印字符组成,包括空格。

    【样例解释】

    • 样例输入
    Hex Dump
    #include <cstdio>
    printf("Hello, World!
    ");
    main = do getLine >>= print . sum . map read . words
    • 样例输出
    0000: 4865 7820 4475 6d70                     hEX dUMP
    0000: 2369 6e63 6c75 6465 203c 6373 7464 696f #INCLUDE <CSTDIO
    0010: 3e                                      >
    0000: 7072 696e 7466 2822 4865 6c6c 6f2c 2057 PRINTF("hELLO, w
    0010: 6f72 6c64 215c 6e22 293b                ORLD!N");
    0000: 6d61 696e 203d 2064 6f20 6765 744c 696e MAIN = DO GETlIN
    0010: 6520 3e3e 3d20 7072 696e 7420 2e20 7375 E >>= PRINT . SU
    0020: 6d20 2e20 6d61 7020 7265 6164 202e 2077 M . MAP READ . W
    0030: 6f72 6473                               ORDS

    解题思路

    暴力写就行。。。使用%x输出十六进制更方便。

    AC代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<string>
    using namespace std;
    char s[5000];
    string str;
    int main() {
        while(gets(s)) {
            int len = strlen(s);
            int tot = 0, res = 0;
            str = " ";
            for(int i = 0; i < len; i++) {
                if(tot == 16) {
                    cout << str << endl;
                    str = " ";
                    tot = 0;
                    res += 16;
                }
                if(s[i] >= 'a' && s[i] <= 'z')str += (s[i] + ('A' - 'a'));
                else if(s[i] >= 'A' && s[i] <= 'Z')str += (s[i] + ('a' - 'A'));
                else str += s[i];
                if(tot == 0) {
                    if(res < 16)printf("000");
                    else if(res < 16 * 16)printf("00");
                    else if(res < 16 * 16 * 16)printf("0");
                    printf("%x:", res);
                }
                if(tot % 2 == 0)printf(" ");
                printf("%x", s[i]);
                tot++;
            }
            if(tot % 2 == 0 && tot != 16)printf(" ");
            for(int i = tot + 1; i <= 16; i++) {
                printf("  "); 
                if(i % 2 == 0 && i != 16)printf(" ");
            }
            if(tot != 0)cout << str << endl;
        }
        return 0;
    }

    E - Number String

    题目大意

    给你一个只包含字符’I’和’D’的字符串,’I’代表当前数字比后面数字值大,’D’代表当前数字比后面数字值小,问你满足该字符串条件的排列的个数%(109+7)。长度为len的串为len+1个数。

    数据范围

    字符串长度为1到1000,只包含’I’,’D’,’?’,’?’代表该位置可以是’I’也可以是’D’。

    解题思路

    首先状态为dp[i][j]代表前i个数以j结尾满足条件的方案数。

    • 即如果第i-1个字符是’I’,即代表第i个数字要比第i-1个数字大,假如第i个数字以j结尾,即dp[i][j]=k=1j1dp[i1][k]
    • 又如果第i-1个字符是’D’,即代表第i个数字要比第i-1个数字小,假如第i个数字以j结尾,即dp[i][j]=k=ji1dp[i1][k]。为什么k可以等于j呢,因为当前i-1个数字最后以j结尾的话,当我第i个数放j时,只要将前面所有大于等于j的数加一,就能保证又满足方案,并且由于前i-1个数最大值是i-1,所以即使加一,在用前i个数时也不会大于i。
    • 如果第i-1个字符是’?’,即为两种情况之和,即dp[i][j]=k=1i1dp[i1][k]

    然后前缀和是可以维护的,其实用一维数组就行,我这写时没想太多。。。

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    const LL Pt = 1e9 + 7;
    const int maxn = 1000;
    LL dp[maxn + 5][maxn + 5];
    LL sum[maxn + 5][maxn + 5];
    char s[maxn + 5];
    int main() {
        while(scanf("%s", s) != EOF) {
            int len = strlen(s);
            memset(dp, 0, sizeof(dp));
            memset(sum, 0, sizeof(dp));
            dp[1][1] = 1LL; sum[1][1] = 1LL, sum[1][0] = sum[0][0] = 0LL;
            for(int i = 2; i <= len + 1; i++) {
                for(int j = 1; j <= i; j++) {
                    if(s[i - 2] == 'I')dp[i][j] = sum[i - 1][j - 1];
                    else if(s[i - 2] == 'D')dp[i][j] = ((sum[i - 1][i - 1] - sum[i - 1][j - 1]) % Pt + Pt) % Pt;
                    else if(s[i - 2] == '?')dp[i][j] = sum[i - 1][i - 1];
                    sum[i][j] = (sum[i][j - 1] + dp[i][j]) % Pt;
                }
            }
            LL res = 0LL;
            for(int i = 1; i <= len + 1; i++)res = (res + dp[len + 1][i]) % Pt;
            printf("%lld
    ", res);
        }
        return 0;
    }

    G - Rescue the Rabbit

    题目大意

    给你n个串,每个串都有一个价值,并让你构造一个只包含’A’,’C’,’G’,’T’四个字母的长度为l的字符串使得总价值最大。只要在字符串l中出现就算一次答案,并且每个串只记一次。

    数据范围

    1n10,1l100,1wi100

    解题思路

    这种题是想不了的,,,,,AC自动机+DP,首先得预处理出以每个结点结尾的取串状态,这个在处理AC自动机的fail指针和Insert时可以处理。然后dp[i][j][k]代表长度为i的串以trie树上第j个结点结尾状态为k的状态是否存在。然后转移的话,第j个结点可以转移到它的下一个结点,并且取串状态也会更新为新的结点加上当前父节点的状态。最后对于所有存在的状态取最大值,记得要滚动一下。。

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<map>
    using namespace std;
    const int maxn = 2000;
    char s[maxn + 5];
    int A[15];
    struct AC_Automaton {
        struct NOOD {
            int next[4];
            int fail, end;
        }node[maxn + 5];
        int size;
        bool dp[2][maxn + 5][maxn + 5];
        void Init() {
            for(int i = 0; i <= maxn; i++) {
                memset(node[i].next, -1, sizeof(node[i].next));
                node[i].fail = 0, node[i].end = 0;
            }
            size = 1;
        }
        int Getx(char c) {
            if(c == 'A')return 0;
            if(c == 'C')return 1;
            if(c == 'G')return 2;
            if(c == 'T')return 3;
        }
        void Insert(char s[], int id) {
            int n = strlen(s);
            int now = 0;
            for(int i = 0; i < n; i++) {
                int x = Getx(s[i]);
                if(node[now].next[x] == -1)node[now].next[x] = size++;
                now = node[now].next[x];
            }
            node[now].end |= (1 << (id - 1));
        }
        void Get_fail() {
            node[0].fail = -1;
            queue<int> que;
            for(int i = 0; i < 4; i++) {
                if(node[0].next[i] == -1)node[0].next[i] = 0;
                else {
                    node[node[0].next[i]].fail = 0;
                    que.push(node[0].next[i]);
                }
            }
            while(!que.empty()) {
                int u = que.front(); que.pop();
                node[u].end |= node[node[u].fail].end;
                for(int i = 0; i < 4; i++) {
                    if(node[u].next[i] == -1)node[u].next[i] = node[node[u].fail].next[i];
                    else {
                        node[node[u].next[i]].fail = node[node[u].fail].next[i];
                        que.push(node[u].next[i]);
                    }
                }
            }
        }
        int Get(int x, int n) {
            int res = 0;
            for(int i = 1; i <= n; i++)
                if((1 << (i - 1)) & x)res += A[i];
            return res;
        }
        void solve(int n, int l) {
            memset(dp[0], 0, sizeof(dp[0]));
            int t = 0; dp[t][0][0] = 1;
            for(int i = 1; i <= l; i++) {
                memset(dp[t ^ 1], 0, sizeof(dp[t ^ 1]));
                for(int j = 0; j < size; j++) {
                    for(int k = 0; k < (1 << n); k++) {
                        for(int x = 0; x < 4; x++) {
                            dp[t ^ 1][node[j].next[x]][k | node[node[j].next[x]].end] |= dp[t][j][k];
                        }
                    }
                }
                t ^= 1;
            }
            int Max = -1;
            for(int i = 0; i < size; i++)
                for(int j = 0; j < (1 << n); j++)
                    if(dp[t][i][j])Max = max(Max, Get(j, n));
            if(Max < 0)printf("No Rabbit after 2012!
    ");
            else printf("%d
    ", Max);
        }
    }AC;
    
    int main() {
        int n, l;
        while(~scanf("%d%d", &n, &l)) {
            AC.Init();
            for(int i = 1; i <= n; i++) {
                scanf("%s %d", s, &A[i]);
                AC.Insert(s, i);
            }
            AC.Get_fail();
            AC.solve(n, l);
        }
        return 0;
    }

    I - The Boss on Mars

    题目大意

    给定一个数n,找出所有与n互质的数的四次方的和。

    数据范围

    T组数据,T1000,1n108

    解题思路

    对于一个数n找出与它互质的数不是很好找,但是找与它有公因子的数还是比较好找的,找出这些数然后用总和减掉就行。但是并不是一下全部找出来减完,而是要用到容斥原理,如果将一个数分成质因子组成的话,比如30 = 2 * 3 * 5;然后要找到所有与它不互质的数,就是要每个质因子即质因子的倍数,这里要减掉所有2的倍数的四次方,再减掉3倍数的四次方,再减掉5倍数的四次方,之后因为会减掉重复的数,比如同时是2和3的倍数,同时是2和5的倍数,同时是3和5的倍数,所以要再加上这些倍数的四次方,然后又会多加,因此又需要再次减掉2和3和5的倍数。就比如要求集合ABC,即可求A+B+C(AB+AC+BC)+ABC。之后求前n项四次方的和需要用到一个公式:

    i=1ni4=n(n+1)(2n+1)(3n2+3n1)/30

    若r是n的因子,要求r所有倍数的的因子可以求r4i=1n/ri4

    AC代码

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long LL;
    const LL Pt = 1e9 + 7;
    LL n;
    vector<LL>ans;
    LL qwe(LL x, LL y) {
        LL t = 1LL;
        while(y > 0LL) {
            if(y & 1)t = t * x % Pt;
            y /= 2LL;
            x = x * x % Pt;
        }
        return t;
    }
    LL Getsum(LL x) {
        return ((x * (x + 1) % Pt * (2 * x + 1) % Pt * (3 * x * x % Pt + 3 * x - 1) % Pt) % Pt + Pt) % Pt * qwe(30, Pt - 2) % Pt;
    }
    int main() {
        int T; scanf("%d", &T);
        while(T--) {
            ans.clear();
            scanf("%lld", &n);
            LL x = n;
            for(LL i = 2LL; i <= sqrt(n); i++) {
                if(x % i == 0LL) {
                    while(x % i == 0)x /= i;
                    ans.push_back(i);
                }
            }
            if(x > 1LL)ans.push_back(x);
            int size = ans.size();
            LL res = 0LL;
            for(int i = 0; i < (1 << size); i++) {
                int tot = 0; LL tmp = 1LL;
                for(int j = 0; j < ans.size(); j++) {
                    if((1 << j) & i) {
                        tmp = tmp * ans[j] % Pt;
                        tot++;
                    }
                }
                LL p = tmp;
                tmp = ((tmp * tmp % Pt) * tmp % Pt) * tmp % Pt;
                if(tot & 1)res = ((res - tmp * Getsum(n / p)) % Pt + Pt) % Pt;
                else res = (res + tmp * Getsum(n / p) % Pt) % Pt;
            }
            printf("%lld
    ", res);
        }
        return 0;
    }
  • 相关阅读:
    (uC/OS-II学习笔记) 事件标志……
    (uC/OS-II学习笔记) 消息邮箱&&消息队列
    (uC/OS-II学习笔记)关于共享资源与信号量
    (uC/OS-II学习笔记)uC/OS-II 时间管理
    (uC/OS-II学习笔记)uC/OS-II在kinetis K60上移植与任务建立
    (Kinetis K60)RTC实时时钟
    (Kinetis K60)flash读写
    JQuery官方学习资料(译):避免与其他库的冲突
    JQuery官方学习资料(译):$( document ).ready()
    JQuery官方学习资料(译):$ vs $()
  • 原文地址:https://www.cnblogs.com/TRDD/p/9813507.html
Copyright © 2020-2023  润新知