其他分享
首页 > 其他分享> > UPC新生训练赛51场

UPC新生训练赛51场

作者:互联网

垃圾本圾了属于是。。。

反正就挺菜的,也就这样, 写写反思吧

问题 A: 优秀的拆分

时间限制: 1.000 Sec  内存限制: 128 MB
提交 状态

题目描述

一般来说,一个正整数可以拆分成若干个正整数的和。例如,1=1,10=1+2+3+4等。
对于正整数n的一种特定拆分,我们称它为“优秀的”,当且仅当在这种拆分下,n被分解为了若干个不同的2的正整数次幂。注意,一个数x能被表示成2的正整数次幂,当且仅当x能通过正整数个2相乘在一起得到。
例如,10=8+2=23+21是一个优秀的拆分。但是,7=4+2+1=22+21+20就不是一个优秀的拆分,因为1不是2的正整数次幂。
现在,给定正整数n,你需要判断这个数的所有拆分中,是否存在优秀的拆分。若存在,请你给出具体的拆分方案。

输入

输入只有一行,一个正整数n,代表需要判断的数。

输出

如果这个数的所有拆分中,存在优秀的拆分。那么,你需要从大到小输出这个拆分中的每一个数,相邻两个数之间用一个空格隔开。可以证明,在规定了拆分数字的顺序后,该拆分方案是唯一的。
若不存在优秀的拆分,输出“-1”(不包含双引号)。

样例输入 Copy

【样例1】
6
【样例2】
7

样例输出 Copy

【样例1】
4 2
【样例2】
-1

提示

样例1解释
6=4+2=22+21是一个优秀的拆分。注意,6=2+2+2不是一个优秀的拆分,因为拆分成的3个数不满足每个数互不相同。

对于20%的数据,n≤10。
对于另外20%的数据,保证n为奇数。
对于另外20%的数据,保证n为2的正整数次幂。
对于80%的数据,n≤1024。
对于100%的数据,1≤n≤1×107。

反思:这个题呢是一个比较正常的位运算题目, 考察的其实就是, 十进制转二进制, 然后倒序输出pow(2, i)就行, 如果第一位是1, 也就是说出现了二的零次方就是no的意思。

代码:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>

using namespace std;
const int N = 1e06 + 10;
typedef long long int ll;

ll q[N], cnt, n;

int main() {
    cin >> n;
    if (n % 2 == 1) {
        cout << -1;
        return 0;
    }
    while (n > 0) {
        q[cnt++] = n % 2;
        n /= 2;
    }

    for (int i = cnt - 1; i > 0; i--) {
        if (q[i] == 1) cout << (int)pow(2, i) << ' ';
    }

    return 0;
}

反正我也是怕超出去就全开的longlong, 没超就行。。。

问题 B: 直播获奖

时间限制: 2.000 Sec  内存限制: 128 MB
提交 状态

题目描述

NOI2130即将举行。为了增加观赏性,CCF决定逐一评出每个选手的成
绩,并直播即时的获奖分数线。本次竞赛的获奖率为w%,即当前排名前w%的选手的最低成绩就是即时的分数线。
更具体地,若当前已评出了p个选手的成绩,则当前计划获奖人数为max(1,⌊p×w%⌋),其中w是获奖百分比,⌊x⌋表示对x向下取整,max(x,y)表示x和y中较大的数。如有选手成绩相同,则所有成绩并列的选手都能获奖,因此实际获奖人数可能比计划中多。
作为评测组的技术人员,请你帮CCF写一个直播程序。

输入

第1行两个正整数n,w。分别代表选手总数与获奖率。
第2行有n个非负整数,依次代表逐一评出的选手成绩。

输出

只有一行,包含n个非负整数,依次代表选手成绩逐一评出后,即时的获奖分数线。相邻两个整数间用一个空格分隔。

样例输入 Copy

【样例1】
10 60 
200 300 400 500 600 600 0 300 200 100 
【样例2】
10 30 
100 100 600 100 100 100 100 100 100 100

样例输出 Copy

【样例1】
200 300 400 400 400 500 400 400 300 300 
【样例2】
100 100 600 600 600 600 100 100 100 100

提示



注意,在第9名选手的成绩评出之后,计划获奖人数为5人,但由于有并列,因此实际会有6人获奖。

对于所有测试点,每个选手的成绩均为不超过600的非负整数,获奖百分比w是一个正整数且1≤w≤99。
在计算计划获奖人数时,如用浮点类型的变量(如C/C++中的float、double,Pascal中的real、double、extended等)存储获奖比例w%,则计算5×60%时的结果可能为3.000001,也可能为2.999999,向下取整后的结果不确定。因此,建议仅使用整型变量,以计算出准确值。

这道题目我写了两个版本结果都超时了

第一个版本:

#include <algorithm>
#include <cmath>
#include <iostream>

using namespace std;
const int N = 1e06 + 10;

int q[N], p[N];

int main() {
    int n, w;
    cin >> n >> w;
    for (int i = 1; i <= n;i++) {
        cin >> q[i];
        sort(q + 1, q + i + 1);
        int mini = max(1, i * w / 100);
        p[i] = q[i - mini + 1];

    }
    for (int i = 1; i <= n; i++) {
        cout << p[i] << ' ';
    }
    return 0;
}

 这一种是最基本的, 就是用排序写的, 但是涉及到排序的话就比较容易超时, 所以我换了第二种方法

#pragma GCC optimize(3,"Ofast","inline")
#include <algorithm>
#include <cmath>
#include <iostream>

using namespace std;
const int N = 1e05 + 10;

int q[N];
int n, w;
int main() {
    cin.tie(0);
    cin >> n >> w;
    q[0] = N;
    for (int i = 1; i <= n; i++) {
        cin >> q[i];
        int t = q[i];
        for (int j = i - 1; j >= 0; j--) {
            if (q[j] < t) {
                q[j + 1] = q[j];
            } else {
                q[j + 1] = t;
                break;
            }
        }
        int k = max(1, i * w / 100);
        cout << q[k] << ' ';
    }
    return 0;
}

哈哈, 这玩意还是陈大佬教我的, 没事就吸口臭氧哈哈;

咳咳!言归正传哈, 这个的方法是比较类似于插入, 然后就省去了排序的功夫, 保证了时间稍微短一点, 每次的话就执行这两个操作, 分别是往后移动和插入。

最后一种方法是能提交过的, 就是说不超时的那种, 就是

#include <bits/stdc++.h>
using namespace std;

int n, w, vh[610], t;

int main() {
    cin >> n >> w;
    for (int i = 1; i <= n; ++i) {
        cin >> t;
        vh[t]++;  //维护哈希表
        int m = max(i * w / 100, 1);
        int p = 601, cnt = 0;
        //统计并求出分数线
        do {
            cnt += vh[--p];
        } while (cnt < m);
        cout << p << " ";
    }
    return 0;
}

注意到成绩为不超过600的非负整数,考虑小学生排序,用简单哈希表统计各分数人数。每加一个成绩:1、维护哈希表,效率:.  2、计算分数线需要从600下向统计总人数,当人数大于等于 m 分数就是分数线,效率:。算法时间复杂度,期望分数:100分。

emmm

然后是E题:

问题 E: 优美的数

时间限制: 1.000 Sec  内存限制: 128 MB
提交 状态

题目描述

在BLUESKY007眼中,如果一个数包含7或这个数是7的倍数,这个数就是优美的。
BLUESKY007在纸上写下了所有大于0的优美的数,她想考考你,第k个数是多少?

输入

第一行一个整数t,表示数据组数。
接下来的t行,每行一个整数k。

输出

一共t行,第i行输出第i组数据的答案。

样例输入 Copy

11
1
2
3
4
5
6
7
8
9
10
2021

样例输出 Copy

7
14
17
21
27
28
35
37
42
47
5477

提示

对于40%的数据,1≤t,k≤10。
对于75%的数据,1≤t,k≤100。
对于100%的数据,1≤t,k≤2021。

水题一枚

#include <iostream>

using namespace std;
const int N = 2200;

int q[N];

int jud(int n) {
    if (n % 7 == 0) return 1;
    while (n) {
        if (n % 10 == 7) return 1;
        n /= 10;
    }
}
void judge() {
    int cnt = 1;
    for (int i = 7; i <= 5477; i++) {
        if (jud(i)) {
            q[cnt++] = i;
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    judge();
    while (n --) {
        int x;
        cin >> x;
        cout << q[x] << endl;
    }

    return 0;
}

简简单单打个表hh

问题G:(俺会的最后一题了

问题 G: Secret Message

时间限制: 1.000 Sec  内存限制: 128 MB
提交 状态

题目描述

Jack and Jill developed a special encryption method, so they can enjoy conversations without worrrying about eavesdroppers. Here is how: let L be the length of the original message, and M be the smallest square number greater than or equal to L. Add (M − L) asterisks to the message, giving a padded message with length M. Use the padded message to fill a table of size K × K, where K2= M. Fill the table in row-major order (top to bottom row, left to right column in each row). Rotate the table 90 degrees clockwise. The encrypted message comes from reading the message in row-major order from the rotated table, omitting any asterisks.

For example, given the original message ‘iloveyouJack’, the message length is L = 12. Thus the padded message is ‘iloveyouJack****’, with length M = 16. Below are the two tables before and after rotation.

Then we read the secret message as ‘Jeiaylcookuv’.

输入

The first line of input is the number of original messages, 1 ≤ N ≤ 100. The following N lines each have a message to encrypt. Each message contains only characters a–z (lower and upper case), and has length 1 ≤ L ≤ 10 000.

输出

For each original message, output the secret message.

样例输入 Copy

2
iloveyoutooJill
TheContestisOver

样例输出 Copy

iteiloylloooJuv
OsoTvtnheiterseC

 叨叨半天啥意思呢, 就是给个n, 表示输入的字符串数, 然后每个字符串分别处理哈, 就是 L 是原始消息的长度,M 是大于或等于 L 的最小平方数。向消息添加 (M − L) 星号,为长度为 M 的填充消息提供填充消息。使用填充消息填充大小为 K × K 的表,其中 K2 = M。按行主顺序(从上到下行, 每行中的从左到右列)。将工作台顺时针旋转 90 度。加密消息来自从旋转的表中按行主顺序读取消息,省略了所有星号。‎

要求就是: 判断长度, 求矩阵大小, 填充进去, 最后加进去星号, clockwise扭转90度然后输出, 星号不输出, 就这回事, 其实很简单, 就是输入我错了好几次, 然后我挨个输出一遍遍改就过了:

代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>

using namespace std;
const int N = 1010;
char bp[N][N];

int get_sqrt(int M) {
    if (M == 1) return 1;
    for (int i = 1; i <= M / i; i++) {
        if (i * i < M && (i + 1) * (i + 1) >= M) {
            return i + 1;
        }
    }
}
int main() {
    int n;
    cin >> n;
    //n++;
    while (n --) {
        //getchar();
        string op;
        cin >> op;
        int M = op.size();
        int k = get_sqrt(M);

        for (int i = 0; i <= k; i++) {
            for (int j = 0; j <= k; j++) {
                bp[i][j] = '*';
            }
        }
        int res = 0;
        for (int i = 1; i <= k; i++) {
            for (int j = 1; j <= k; j++) {
                if (res < op.size()) {
                    bp[i][j] = op[res];
                    res ++;
                } else {
                    bp[i][j] = '*';
                }
                //cout << bp[i][j] << ' ';
            }
            //cout << endl;
        }
        for (int i = 1; i <= k; i++) {
            for (int j = k; j >= 1; j--) {
                if (bp[j][i] != '*') {
                    cout << bp[j][i];
                }
            }
        }
        puts("");
    }

    return 0;
}

然后做个总结吧, 拉跨是拉跨一点, 但是吧希望自己能够坚持下去, 反正别开摆就行, 好好学算法,专心准备比赛, 多多反思, 整理。

标签:10,新生训练,int,样例,51,UPC,100,include,message
来源: https://blog.csdn.net/beloved_yu/article/details/123588940