zoukankan      html  css  js  c++  java
  • 解题报告(18.06.02)

    选拔考试

    T1
    小K手中有n张牌,每张牌上有一个一位数的数,这个字数不是0就是5。小K从这些牌在抽出任意张(不能抽0张),排成一行这样就组成了一个数。使得这个数尽可能大,而且可以被90整除。

    样例

    Input:
    4
    5 0 5 0

    Output:
    0

    思路
    被90整除即同时被9和10整除,被10整除则至少有一个0,被9整除则5的个数为9的倍数,简单题

    直接上代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define CL(X,N) memset(X, N, sizeof(X))
    #define LL long long
    using namespace std;
    const int maxn=1e3+10;
    int a[maxn], n;
    int cnt5=0, cnt0=0;
    
    inline void _init() {
        freopen("zaf.in", "r", stdin);
        freopen("zaf.out", "w", stdout);
    }
    
    int main() {
        _init();
        scanf("%d", &n);
        for(int i=0; i<n; i++) {
            scanf("%d", a+i);
            if(a[i]==5) cnt5++;
            if(a[i]==0) cnt0++;
        }
        if(!cnt0) {
            printf("-1");
            return 0;
        }
        int ls=cnt5/9;
        if(ls){
            for(int i=0; i<ls*9; i++) printf("5");
            for(int i=0; i<cnt0; i++) printf("0");
        } else printf("0");
        return 0;
    }

     

    这么简单,不想打注释


    T2

    现在有一块玻璃,是长方形的(w 毫米× h 毫米),现在要对他进行切割。切割的方向有两种,横向和纵向。每一次切割之后就会有若干块玻璃被分成两块更小的玻璃。在切割之后玻璃不会被移动。
    现在想知道每次切割之后面积最大的一块玻璃是多少。

    样例

    Input:
    4 3 4
    H 2
    V 2
    V 3
    V 1

    Output:
    8
    4
    4
    2

    样例解释


    对于第四次切割,下面四块玻璃的面积是一样大的。都是2

    思路

    标准思路:倒过来处理,如果当前位置x是割线,那么 H[x].l表示该割线左面那条割线的位置, H[x].r表示该割线右面那条割线的位置, H[i].val表示该割线与左面那条割线之间的长度, 这样每次增加割线倒过来之后就相当于删除割线, 当然每次删除只要O(1)更新这条割线左右两边割线的值就好,每次答案就是max(H[i].val)*max(V[i].val),i∈[0,w(h)] ,总复杂度:O(n)

    当时思路
    为了避免TLE,先将操作存下来,并标记先后(将上下左右边界也存进去,id设为0),按位置排序后,正向跑for并记录最大的当前宽度和高度,依次输出结果(其实差不多)

    燃鹅,令我懵逼的是,有人每读入一个操作就sort一次,然后跑for,居然也没TLE(一定是数据太水)

    然后放代码吧:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #define CL(X,N) memset(X, N, sizeof(X))
    #define LL long long
    using namespace std;
    const int maxn=2e5+10;
    int w, h, n;
    struct cut {
        LL x;
        int id;
        cut(){}
        cut(LL _x, int _id) : x(_x), id(_id) {}
    }wl[maxn], hl[maxn];
    
    bool cmp(cut a, cut b) {
        return a.x<b.x;
    }
    
    inline void _init() {
        freopen("cut.in", "r", stdin);
        freopen("cut.out", "w", stdout);
    }
    
    int cnth=2, cntw=2;
    
    int main() {
        _init();
        scanf("%d%d%d", &w, &h, &n);
        wl[0]=cut(0, 0);
        wl[1]=cut(w, 0);
        hl[0]=cut(0, 0);
        hl[1]=cut(h, 0); //初始化
        for(int i=1; i<=n; i++) {
            char cmd[2];
            LL x;
            scanf("%s", cmd); //把'
    '吞掉
            scanf("%d", &x);
            if(cmd[0]=='H') {
                hl[cnth++]=cut(x, i);
            } else if(cmd[0]=='V') {
                wl[cntw++]=cut(x, i);
            }
        }
        sort(wl, wl+cntw, cmp);
        sort(hl, hl+cnth, cmp);
        for(int i=1; i<=n; i++) {
            LL answ=0, ansh=0;
            LL lastw=0, lasth=0;
            for(int j=1; j<cntw; j++) {
                if(wl[j].id>i) continue;
                answ=max(answ, wl[j].x-lastw); //计算最大宽度
                lastw=wl[j].x;
            }
            for(int j=1; j<cnth; j++) {
                if(hl[j].id>i) continue;
                ansh=max(ansh, hl[j].x-lasth); //最大高度
                lasth=hl[j].x;
            }
            printf("%lld
    ", answ*ansh);
        }
        return 0;
    }

    标程:

     

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    const int MAXN = 2e5 + 10;
    
    int maxW, maxH;
    int preW[MAXN], preH[MAXN];
    int rankW[MAXN], rankH[MAXN];
    int visW[MAXN], visH[MAXN];
    
    int w, h, n;
    
    char opt[3];
    int op[MAXN];
    int num[MAXN];
    long long ans[MAXN];
    
    inline void scan_d(int &ret)
    {
        char c;
        ret = 0;
        while ((c = getchar()) < '0' || c > '9');
        while (c >= '0' && c <= '9')
        {
            ret = ret * 10 + (c - '0'), c = getchar();
        }
    }
    
    int findW(int x)
    {
        if (preW[x] != x)
        {
            preW[x] = findW(preW[x]);
        }
        return preW[x];
    }
    
    void joinW(int x, int y)
    {
        x = findW(x);
        y = findW(y);
    
        if (x == y)
        {
            return ;
        }
    
        preW[y] = x;
        rankW[x] += rankW[y];
        maxW = max(rankW[x], maxW);
    }
    
    int findH(int x)
    {
        if (preH[x] != x)
        {
            preH[x] = findH(preH[x]);
        }
        return preH[x];
    }
    
    void joinH(int x, int y)
    {
        x = findH(x);
        y = findH(y);
    
        if (x == y)
        {
            return ;
        }
    
        preH[y] = x;
        rankH[x] += rankH[y];
    
        maxH = max(rankH[x], maxH);
    }
    
    void init()
    {
        for (int i = 0; i <= w; i++)
        {
            preW[i] = i;
            rankW[i] = 1;
        }
        for (int i = 0; i <= h; i++)
        {
            preH[i] = i;
            rankH[i] = 1;
        }
        memset(visW, 0, sizeof(visW));
        memset(visH, 0, sizeof(visH));
        memset(op, 0, sizeof(op));
    }
    
    int main()
    {    
        freopen("cut.in","r",stdin);
        freopen("cut.out","w",stdout);
        cin >> w >> h >> n;
    
        init();
    
        rankW[0] = rankH[0] = 0;
    
        for (int i = 0; i < n; i++)
        {
            scanf("%s", opt);
            scan_d(num[i]);
    
            if (opt[0] == 'H')
            {
                op[i] = 1;
                visH[num[i]] = 1;
            }
            else
            {
                visW[num[i]] = 1;
            }
        }
    
        maxH = 1;
        maxW = 1;
    
        for (int i = 1; i < w; i++)
        {
            if (!visW[i])
            {
                joinW(i, i + 1);
            }
        }
    
        for (int i = 1; i < h; i++)
        {
            if (!visH[i])
            {
                joinH(i, i + 1);
            }
        }
    
        for (int i = n - 1; i >= 0; i--)
        {
            ans[i] = (long long)(maxH) * (maxW);
    
            if (op[i])
            {
                joinH(num[i], num[i] + 1);
            }
            else
            {
                joinW(num[i], num[i] + 1);
            }
        }
    
    
        for (int i = 0; i < n; i++)
        {  
            printf("%lld
    ", ans[i]);
        }  
    
        return 0;  
    }

     


    T3

    小H是个善于思考的学生,现在她又在思考一个有关序列的问题。
    她的面前浮现出一个长度为n的序列{ai},她想找出一段区间[L, R](1 <= L <= R <= n)。
    这个特殊区间满足,存在一个k(L <= k <= R),并且对于任意的i(L <= i <= R),ai都能被ak整除。这样的一个特殊区间 [L, R]价值为R - L。
    小H想知道序列中所有特殊区间的最大价值是多少,而有多少个这样的区间呢?这些区间又分别是哪些呢?你能帮助她吧。

    【输入格式】
    第一行,一个整数n.
    第二行,n个整数,代表ai.

    【输出格式】
    第一行两个整数,num和val,表示价值最大的特殊区间的个数以及最大价值。
    第二行num个整数,按升序输出每个价值最大的特殊区间的L.

    样例

    Input:
    5
    4 6 9 3 6

    Output:
    1 3
    2

    【数据范围】
    30%: 1 <= n <= 30 , 1 <= ai <= 32.
    60%: 1 <= n <= 3000 , 1 <= ai <= 1024.
    80%: 1 <= n <= 300000 , 1 <= ai <= 1048576.
    100%: 1 <= n <= 500000 , 1 <= ai < 2 ^ 31.

    思路

    标准思路
    30% :暴力枚举判断。O(n^4)。
    60% :特殊区间的特点实际上就是区间最小值等于这个区间的GCD,于是暴力或递推算出每个区间最小值与GCD。而对于最大价值,可以通过二分来进行求解。复杂度O(n ^ 2)。
    100%:在60%的基础上,最小值与GCD都使用RMQ算法来求解,对于这道题推荐使用ST表。最大价值仍然使用二分。复杂度O(nlogn)。

    当时思路:
    当看到数据范围时,我真的方了,说真的,当时就觉得跑一个for已经极限了,跑两个for就该TLE了,GCD更容易TLE(还要判断区间GCD,真不敢写),燃鹅,我还是毅然决然的暴力(想不到更好的方法了),最后写了一个O(n^2)的,真的听天由命了

    但是,我居然过了(hahahaha...),真心高兴

    然后上代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define CL(X,N) memset(X, N, sizeof(X))
    #define LL long long
    using namespace std;
    const int maxn=5e5+10;
    int n;
    int a[maxn];
    int l[maxn]={0}, maxlen=0, num=0;
    int vis[maxn];
    
    inline void _init() {
        freopen("pair.in", "r", stdin);
        freopen("pair.out", "w", stdout);
    }
    
    int main() {
        //_init();
        CL(vis, -1);
        scanf("%d", &n);
        for(int i=1; i<=n; i++) {
            scanf("%d", a+i);
        }
        for(int i=1; i<=n; i++) {
            int ll=i, rr=i;
            while(ll>1 && !(a[ll-1]%a[i])) ll--;
            while(rr<n && !(a[rr+1]%a[i])) rr++;
            if(rr-ll>maxlen) {
                num=0;
                maxlen=rr-ll;
            }
            if(rr-ll==maxlen && vis[ll]!=maxlen) {
                l[num++]=ll;
                vis[ll]=maxlen;
            }
        }
        printf("%d %d
    ", num, maxlen);
        for(int i=0; i<num; i++) printf("%d ", l[i]);
        return 0;
    }

    标程:

     

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    const int N = 5e5 + 3, M = 21;
    int n, m, a, ans, l, r, mid, sum, A[N], f[N][M], g[N][M], p[M];
    
    inline int Gcd(const int &x, const int &y) {
        return y == 0 ? x : Gcd(y, x % y);
    }
    
    bool check(int len) {
        int q = log2(len--), k = n + 1 - p[q], j;
        for (int i = 1; i <= k; ++i) {
            j = i + len;
            if (min(f[i][q], f[j - p[q] + 1][q]) == Gcd(g[i][q], g[j - p[q] + 1][q]))
                return true;
        }
        return false;
    }
    
    char ch;
    inline int read() {
        while (ch = getchar(), ch < '0' || ch > '9');
        int res = ch - 48;
        while (ch = getchar(), ch >= '0' && ch <= '9') res = res * 10 + ch - 48;
        return res;
    }
    
    char s[10];
    inline void print(int x) {
        int res = 0;
        if (x == 0) putchar('0');
        while (x) {
            s[++res] = x % 10;
            x /= 10;
        }
        for (int i = res; i; --i) putchar(s[i] + '0');
        putchar(' ');
        return ;
    }
    
    int main() {
        freopen("pair.in", "r", stdin);
        freopen("pair.out", "w", stdout);
        n = read(); m = log2(n);
        for (int i = 1; i <= n; ++i) {
            a = read();
            f[i][0] = g[i][0] = a;
        }
        for (int i = 0; i <= m; ++i) p[i] = 1 << i;
        for (int j = 1; j <= m; ++j) {
            int k = n + 1 - p[j];
            for (int i = 1; i <= k; ++i) {
                f[i][j] = min(f[i][j - 1], f[i + p[j - 1]][j - 1]);
                g[i][j] = Gcd(g[i][j - 1], g[i + p[j - 1]][j - 1]);
            }
        }
        l = 1; r = n;
        while (l <= r) {
            mid = l + r >> 1;
            if (check(mid)) l = mid + 1;
            else     r = mid - 1;
        }
        ans = r;
        if (ans == 1) {
            printf("%d %d
    ", n, 0);
            for (int i = 1; i < n; ++i)
                print(i);
            printf("%d
    ", n);
        }
        else {
            int q = log2(ans--), k = n + 1 - p[q], j;
            for (int i = 1; i <= k; ++i) {
                j = i + ans;
                if (min(f[i][q], f[j - p[q] + 1][q]) == Gcd(g[i][q], g[j - p[q] + 1][q]))
                    A[++sum] = i;
            }
            printf("%d %d
    ", sum, ans);
            for (int i = 1; i < sum; ++i)
                print(A[i]);
            printf("%d
    ", A[sum]);
        }
        fclose(stdin); fclose(stdout);
        return 0;
    }

    T4:

    给定一个{0, 1, 2, 3, … , n - 1}的排列 p。一个{0, 1, 2 , … , n - 2}的排列q被认为是优美的排列,当且仅当q满足下列条件:

    对排列s = {0, 1, 2, 3, ..., n - 1}进行n – 1次交换。

    1. 交换s[q0],s[q0 + 1]
    2. 交换s[q1],s[q1 + 1]

    最后能使得排列s = p.
    问有多少个优美的排列,答案对10^9+7取模。

    【输入格式】

    第一行一个正整数n.

    第二行n个整数代表排列p.

     

    【输出格式】

             仅一行表示答案。

     

    【样例输入】

    3

    1 2 0

     

    【样例输出】

    1

     

    【样例解释】

    q = {0,1} {0,1,2} ->{1,0,2} -> {1, 2, 0}

    q = {1,0} {0,1,2} ->{0,2,1} -> {2, 0, 1}

     

    【数据范围】

    30%:  n <= 10

    100%:  n <= 50

    思路:

    30%:

           枚举所有排列,判定即可。

    100%:

           考虑倒着处理,比如交换 (i, i + 1),那么前面的所有数不管怎么交换都无法到后面去(下标恒小于等于i),后面的数也是一样到不了前面。说明这最后一次交换前,就要求对于所有的 x <= i, y > i,px<py。所以交换前左边的数是连续的,右边也是连续的。由于交换前,前面和后面的数是互相不干涉的,所以就归结成了两个子问题。于是我们可以用记忆化搜索来解决这个问题。

           设dp[n][low] 代表长度为n,H是{low, low + 1,…,low + n - 1}的排列,且H是p的子序列,在H上优美序列的个数。

           我们枚举交换哪两个相邻元素(k,k+1),然后判断k前面的所有数是否都小于后面的所有数,如果是则进行转移dp[n][low] += dp[k][low] * dp[n – k][low + k ] * C(n – 2, n – 1 - k)。

    即前面的k个元素与后面的n - k个元素是两个独立的子问题,前面是{low ... low + k - 1}的排列,后面是{low + k ... low + n - 1}的排列,C(n - 2, n - 1 - k)代表的是在交换(k, k + 1)前左右两边还分别要进行n - 2次交换,而每次交换左边与交换右边是不同方案,这相当于n - 2个位置选择n - 1 - k个位置填入,故还需要乘上C(n - 2, n - 1 - k)。时间复杂度为O(n^4)。

    标程:

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    typedef long long ll;
    const int N = 52, Mod = 1e9 + 7;
    int n, p[N], dp[N][N], C[N][N];
    
    int Dfs(int len, int low) {
        if (dp[len][low] != -1) return dp[len][low];
        if (len == 1) return dp[len][low] = 1;
        int &res = dp[len][low]; res = 0;
        int t[N], m = 0, j, k;
        for (int i = 1; i <= n; ++i)
            if (p[i] >= low && p[i] < low + len)
                t[++m] = p[i];
        for (int i = 1; i < m; ++i) {
            swap(t[i], t[i + 1]);
            for (j = 1; j <= i; ++j)
                if (t[j] >= low + i) break;
            for (k = i + 1; k <= m; ++k)
                if (t[k] < low + i) break;
            if (j > i && k > m) {
                ll tmp = (ll)Dfs(i, low) * Dfs(m - i, low + i) % Mod;
                tmp = tmp * C[m - 2][i - 1] % Mod;
                res = (res + tmp) % Mod;
            }
            swap(t[i], t[i + 1]);
        }
        return res;    
    }
    
    int main() {
        freopen("swap.in", "r", stdin);
        freopen("swap.out", "w", stdout);
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) scanf("%d", &p[i]);
        memset(dp, -1, sizeof(dp));
        for (int i = 0; i <= n; ++i) {
            C[i][0] = 1;
            for (int j = 1; j <= i; ++j)
                C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % Mod;
        }
        Dfs(n, 0);
        if (dp[n][0] != -1) cout << dp[n][0] << endl;
        else     puts("0");
        fclose(stdin); fclose(stdout);
        return 0;
    }

    只有标程,因为没做出来...

  • 相关阅读:
    写在“开张”时
    上班真累
    版本控制
    电脑主板报警声音的故障现象对照表
    js页面打开倒计时
    js中的词法分析
    修改mysql数据库密码
    上班的感受
    能力是被逼出来的!!有压力才有动力
    js中绑定事件的三种方式
  • 原文地址:https://www.cnblogs.com/normaldisk/p/9127340.html
Copyright © 2011-2022 走看看