解题报告(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); //把'\n'吞掉
        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\n", answ*ansh);
    }
    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\n", num, maxlen);
    for(int i=0; i<num; i++) printf("%d ", l[i]);
    return 0;
}

题目就先到这里了

还有一件事,inline内联函数后是需要返回值的,如void,不知为毛_init()前不加void在我的本地也能过编译,最后提交后编译失败,把我吓的...还好允许改回来,还是得了分

这个神奇的本地通过真心迷...(不知道有没有人和我一样)

猜你喜欢

转载自www.cnblogs.com/normaldisk/p/9127340.html