zoukankan      html  css  js  c++  java
  • 开学第一测

                        开学第一测

                    (NOIP模拟题)

    T1        (期望得分:100;实际得分:100)

    循环移动

    (cyclic.cpp/c/pas)

    (1s/256M)

    问题描述

    给出一个字符串S与N个操作。每个操作用三元组(L, R, K)进行描述:操作将字符串第L个到第R个位置构成的子串循环移动K次。一次循环移动就是将字符串最后的这个字符移动到第一位,其余的字符顺次后移。

    例如,对于字符串abacaba,操作(L=3, R=6, K=1)后得到的字符串即为abbacaa。

    求出在N个操作后得到的字符串。

    输入格式(cyclic.in)

    第一行一个字符串S。

    第二行一个整数N,代表操作的总数。

    接下来N行每行三个数L,R,K,每行代表一个操作。

    输出格式(cyclic.out)

    一行一个字符串,代表N个操作后的字符串。

    样例输入

    abbacaa

    2

    3 6 1

    1 4 2

    样例输出

    ababaca

    数据范围与约束

    设|S|为字符串S的长度。

    对于30%的数据,|S|<=100, N<=100, K<=100

    对于100%的数据,|S|<=10000, N<=300, K<=1000,000,1<=L<=R<=|S|

    思路:字符串处理           难度:普及+

    代码如下(第一个是我的,第二个是学姐(TRTTG)的):

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int n, l, r, t;    //见题目
    char ch[10005];    //记录字符串
    void change(int l, int r, int t) {
        int tot = 0, tmp = 0;
        char arr[10005];    //记录区间后要移到前边的字符
        for(int i = r-t+1; i <= r; i++)    //转移
            arr[++tot] = ch[i];
        for(int i = r-t; i>=l; i--)
            ch[i+t] = ch[i];
        for(int i = l; i <= l+tot-1; i++)
            ch[i] = arr[++tmp];
    }
    int main() {
        freopen("cyclic.in","r",stdin);
        freopen("cyclic.out","w",stdout);
        gets(ch);
        int len = strlen(ch);
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d%d%d", &l, &r, &t);
            t %= (r-l+1);
            change(l-1, r-1, t);
        }
        puts(ch);
        fclose(stdin); fclose(stdout);
        return 0;
    }
    cyclic.cpp
    #include <string>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int N = 10005;
    
    int n;
    
    string str;
    int tmp[N];
    
    int main()
    {
        freopen("cyclic.in", "r", stdin);
        freopen("cyclic.out", "w", stdout);
    
        cin >> str;
    
        cin >> n;
    
        for(int i = 0; i < n; ++ i)
        {
            int x, y, k;
    
            cin >> x >> y >> k;
            -- x, k %= (y - x);
    
            int cnt = 0;
            for(int j = y - k; j < y; ++ j) tmp[cnt ++] = str[j];
            for(int j = y - 1; j >= x + k; -- j) str[j] = str[j-k];
            for(int j = x; j < x + k; ++ j) str[j] = tmp[j - x];
        }
    
        cout << str << endl;
    
        return 0;
    }
    cyclic2.cpp

    T2          (期望得分:100;实际得分:0)                                

    阅读计划

    (book.cpp/c/pas)

    (1s/256M)

    问题描述

    暑假到了,Rick制定了一个长达M天的阅读计划。他一共有N本书,从1至N进行标号;Rick将它们从上至下摞成一堆。他每天都会读一本书,假设他要读编号为X的书,他会按照以下步骤:

    1. 将这本书上方的所有书搬起来

    2. 将这本书拿出来

    3. 将搬起来的书摞回去

    4. 看完后把这本书放到顶端

    每本书都会有各自的重量,Rick不希望搬起太过重的书。于是他希望能重新安排这N本书的顺序,使得读完M本书之后,搬书的重量之和最小。

    输入格式(book.in)

    第一行两个整数N与M,分别代表书的数量和阅读的天数。

    第二行N个整数,代表每本书的重量。

    第三行M个整数,代表每天要读的书的编号。

    输出格式(book.out)

    一行一个整数,代表最小的重量之和。

    样例输入

    3 5

    1 2 3

    1 3 2 3 1

    样例输出

    12

    数据范围与约束

    对于30%的数据,N<=10.

    对于100%的数据,2<=N<=500, 1<=M<=1000, 每本书重量不超过100.

    考察算法:贪心(虽然考试时我也是用的贪心,but贪错了qwq)            难度:提高

    思路:1. 如果只读一本书,直接放在最上面;

        2.如果只读两本书,考虑第一本:无论怎样第一天后都会放到顶上,那不如就直接放在顶上。那么,第二本书放在第二个位置是最优的;

           3.如果只读三本书,类似的,考虑第三本:在读完前两本后,他们肯定会放在最上方,所以放在第三位置最优。(如果放到上面,会给其他书增加重量)

         So,贪心策略为:按照阅读顺序从上往下放

    代码如下(我的就不拿出来丢人了):

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int N = 3005;
    
    int n, m;
    int a[N], b[N];
    int p[N], fg[N];
    
    int main()
    {
        freopen("book.in", "r", stdin);
        freopen("book.out", "w", stdout);
    
        cin >> n >> m;
        for(int i = 1; i <= n; ++ i) cin >> a[i];
        for(int i = 1; i <= m; ++ i) cin >> b[i];
    
        for(int i = 1; i <= n; ++ i) fg[i] = 0;
    
        p[0] = 0;
        for(int i = 1; i <= m; ++ i)
        {
            int u = b[i];
            if(!fg[u]) p[++p[0]] = u, fg[u] = 1;
        }
    
        int ans = 0;
    
        for(int i = 1; i <= m; ++ i)
        {
            int u = b[i], j;
            for(j = 1; p[j] != u; ++ j) ans += a[p[j]];
            for(; j > 1; -- j) p[j] = p[j-1];
            p[1] = u;
        }
    
        cout << ans << endl;
    
        return 0;
    }
    book.cpp

    T3            (期望得分:0;实际得分:0 qwq)

    树集

    (set.cpp/c/pas)

    (1s/256M)

    问题描述

    给出一棵N个节点的树,每个节点上都附有一个权值ai。现在Ann想从中选出若干个节点,满足以下条件:

    1. 至少选出一个节点

    2. 节点之间是连通的

    3. 设节点中权值最大的为ap,最小的为aq,则需要满足ap-aq不大于某个定值D。

    Ann想知道有多少种选择的方式?结果对1,000,000,007取模即可。

    输入格式(set.in)

    第一行包含两个整数D, N,分别代表定值D与节点总数N。

    第二行包含N个整数ai,分别代表每个点的权值。

    接下来N-1行,每行包含两个数u, v,代表树中节点u与节点v是相连的。

    输出格式(set.out)

    一个整数,代表方案数模1,000,000,007的结果。

    样例输入

    1 4

    2 1 3 2

    1 2

    1 3

    3 4

    样例输出

    8

    样例解释

    8个选择方式为:{1}, {2}, {3}, {4}, {1, 2}, {1, 3}, {3, 4}, {1, 3, 4}。

    数据范围与约束

    对于30% 的数据,1<=n<=10;

    对于另外的30% 的数据,d=2000.

    对于100% 的数据,0<=d<=2000, 1<=n<=2000, 1<=ai<=2000.

    考察算法:动态规划(DP)/ 树         难度:提高

    思路:

      30%(1<=n<=10) :暴力枚举搜索

      60%(D=2000) :由数据知:最大值与最小值的差一定小于D ,所以只需求出有多少不同的联通集即可;  采用树形DP:设 f[i] 为以 i 为根的子树,而且必须要取节点 i 的方案数是多少。  DP方程:f[i] = Π ( f[x] + 1)   (x为 i 的儿子)

      100%  :枚举集合中最小的节点 x ,则能够在集合里的节点 y 必须满足 A[x] <= A[y] <= A[x] + D。  从 x 出发,遍历这样的 y 节点。显然(我也不知道显然在哪里,题解上是这么说的),其余的节点都不能在集合中(权值不满足 或 不连通)      可以用DP算出以 x 为跟的结果

    依旧是学姐的代码:

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int N = 2005;
    const int MOD = 1e9 + 7;
    
    int d, n;
    int a[N];
    
    int rt, al, ar;
    
    int f[N];
    
    vector<int> e[N];
    
    void dfs(int x, int y)
    {
        f[x] = 1;
    
        for(unsigned i = 0; i < e[x].size(); ++ i)
        {
            int u = e[x][i];
    
            if(a[u] < al || a[u] > ar || u == y) continue;
            if(a[u] == al && u < rt) continue;
    
            dfs(u, x);
            f[x] = 1LL * f[x] * (f[u] + 1) % MOD;
        }
    }
    
    int main()
    {
        freopen("set.in", "r", stdin);
        freopen("set.out", "w", stdout);
    
        cin >> d >> n;
    
        for(int i = 1; i <= n; ++ i) cin >> a[i];
    
        for(int i = 1, x, y; i < n; ++ i)
        {
            cin >> x >> y;
            e[x].push_back(y);
            e[y].push_back(x);
        }
    
        int ans = 0;
    
        for(int i = 1; i <= n; ++ i)
        {
            rt = i;
            al = a[i];
            ar = a[i] + d;
    
            dfs(i, 0);
    
            (ans += f[i]) %= MOD;
        }
    
        cout << ans << endl;
    
        return 0;
    }
    set.cpp
  • 相关阅读:
    反悔贪心 学习笔记
    「CF901C」Bipartite Segments 题解
    「HEOI2015」公约数数列 题解
    拓展欧拉定理
    莫比乌斯反演题目选做
    八月水题录
    chapt15、使用虚拟内存
    chapt16、线程堆栈
    chapt14、探索虚拟内存
    get files version by vbs
  • 原文地址:https://www.cnblogs.com/v-vip/p/8505967.html
Copyright © 2011-2022 走看看