第八届“图灵杯”NEUQ-ACM程序设计竞赛个人赛

A 切蛋糕

大意:

现在有一个蛋糕,需要分给k个人,每次操作可以将一个蛋糕分为2份,还可以选择一些蛋糕打包为一份,最后需要打包出k份,使得每一份的蛋糕量为1/k,误差不大于1e-10,全部操作需要在6000步内完成‘

k保证不大于2e10

思路:

直接将所有的蛋糕分为1/1e-10,这样需要的操作数为2e11-1,也就是2047次,然后打包出k份,操作次数不超过2e10,总体不超过2047+1024次,小于6000次

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
int const MAXN = 2e5 + 10;
int n, m, T;
int two[15];
void init()
{
    two[0] = 1;
    for (int i = 1; i < 13; i++)
    {
        two[i] = 2 * two[i - 1];
    }
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n;
    init();
    cout << two[11] - 1 + n << endl;    
    int cnt = 0;
    for (int i = 0; i <= 10; i++)
    {
        for (int j = 0; j < two[i]; j++)
        {
            cout << 1 << " " << i << endl;
        }
    }
    double ans = 1.0 / n
    int num = ans / (1.0 / two[11]);
    for (int i = 0; i < n; i++)
    {
        cout << 2 << " " << num;
        for (int j = 0; j < num; j++)
            cout << " " << 11;
        cout << endl;
    }
    return 0;
}

B 小宝的幸运数组

大意:

给出一个长度为n的数组,要求找到一个区间使得区间和为k的倍数,如果有的话输出最长的区间长度,否则输出-1

思路:

记录前缀和出现的最早位置,然后相减即可,需要每次都模k,这样保证区间和是k的倍数

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
int t, n, r;

LL sum[N], a[N], k;
map<LL, int> mp;
int main() {
    cin >> t;
    while (t--) {
        cin >> n >> k;
        mp.clear();
        int res = -1;
        mp[0] = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            sum[i] = (sum[i - 1] + a[i] % k) % k;
            if(mp.count(sum[i])){
                res = max(res, i - mp[sum[i]]);
            }
            else
                mp[sum[i]] = i;
        }
        cout << res << endl;
    }
    return 0;
}

C 上进的凡凡

大意:

给出长度为n的数组,求出其中不下降子数组的数量

思路:

直接扫一遍,如果遇到长度为k的不下降子数组,那么答案应该加上1到k的累加和

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
int const N = 2e5 + 10;
LL n, m, T;
LL a[N];
LL jie[N+10];
void init(){
    jie[0]=jie[1]=1;
    for(int i=2;i<=N;i++){
        jie[i]=jie[i-1]+i;
    }
}
int main() {
    cin>>n;
    init();
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    LL num=0;
    LL ans=0;
    for(int i=1;i<=n;i++){
        if(a[i]>=a[i-1]) num++;
        else{
            ans+=jie[num];
            num=1;
        }
    }
    ans+=jie[num];
    cout<<ans<<endl;
    return 0;
}

D Seek the Joker I

大意:

一共n个数的堆,从上到下开始取,每次最少取1个,最多取k个,取到最后一个的为输

先手赢输出yo xi no forever!

后手赢输出ma la se mi no.1!

思路:

巴什博弈裸题

#include<bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
int t, n, k;
int main(){
    cin >> t;
    while(t--){
        cin >> n >> k;
        if (n % (k + 1) == 1) cout << "ma la se mi no.1!" << endl;
        else
            cout << "yo xi no forever!" << endl;
    }
    return 0;
}

E Seek the Joker II

大意:

一个n个数的堆,每次可以从上面取任意个数,或者从下面取任意个数,或者同时从上面和下面取相同多个数,取到原来第x个的为输

先手赢输出yo xi no forever!

后手赢输出ma la se mi no.1!

思路:

威佐夫博弈裸题

#include <bits/stdc++.h>
using namespace std;
int T;
int main() {
    int n1,n2,temp, n, x;
    cin >> T;
    while(T--) {
        cin >> n >> x;
        n1 = x - 1, n2 = n - n1 - 1;
        if(n1>n2)  swap(n1,n2);
        temp=floor((n2-n1)*(1+sqrt(5.0))/2.0);
        if(temp==n1) cout<<"ma la se mi no.1!"<<endl;
        else cout<<"yo xi no forever!"<<endl;
    }
    return 0;
}

F 成绩查询ing

大意:

给出n个人的学号、成绩、性别、姓名

然后是m次查询,如果输入的是成绩,则输出全部的成绩为这个成绩的学生的姓名(按字典序)

如果查询的是姓名,则输出学生的成绩

思路:

直接模拟即可,但是由于n和m比较大,直接查询会超时,但是由于成绩的范围都是1到100,所以可以首先预处理出1到100分的答案,查询的时候直接输出即可

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
int const N = 1e5 + 10;
int n, m;
unordered_map<string,PIII> mp;
unordered_map<int,set<string>> grade_name;
string g[N];
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n;
    for(int i=0;i<n;i++){
        string name;
        int grade,sex,num;
        cin>>name>>grade>>sex>>num;
        PII sex_num={sex,num};
        mp[name]={grade,sex_num};
        grade_name[grade].insert(name);
    }
    for(auto it=grade_name.begin();it!=grade_name.end();it++){
        string s="";
        for(auto i=it->second.begin();i!=it->second.end();i++){
            s=s+(*i);
            s+="
";
        }
        g[it->first]=s;
    }
    cin>>m;
    while(m--){
        int t;
        cin>>t;
        if(t==1){
            string name;
            cin>>name;
            //PIII gsn = mp[name];
            cout<<mp[name].first<<" "<<mp[name].second.second<<" "<<mp[name].second.first<<endl;
        }
        else{
            int grade;
            cin>>grade;
            cout<<g[grade];
        }
    }
    
    return 0;
}

G 贪吃的派蒙

大意:

n个人,k份蛋糕。每个人都可以有一个饭量ai,每次轮到一个人的时候,可以取1到ai份蛋糕

但是这n个人里面有一个贪心者派蒙,他是ai最大的那个人,他一定会取走ai份饭

所以现在大家想让他刷盘子,也就是最后一个取完蛋糕,问能否使他最后一个取完全部的蛋糕

注意取完n个人一轮后,如果还有蛋糕,则从第1个人开始取第二轮

思路:

直接每一轮模拟即可,从左到右算最小值和最大值,看能否将派蒙包含进里面即可

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
LL n, k, t;
queue<LL> q;
int main() {
    cin >> t;
    while (t--) {
        cin >> n >> k;
        LL p = 0;
        while(!q.empty()) q.pop();
        for (int i = 0; i < n; i++) {
            LL x;
            cin >> x;
            p = max(p, x);
            q.push(x);
        }
        LL l = 0, r = 0;
        while (1) {
            LL x = q.front();
            q.pop();

            if (x == p) {
                r += x;
                if (k > l && k <= r) {
                    cout << "YES
";
                    break;
                }
                if (k <= l) {
                    cout << "NO
";
                    break;
                }
                l += x;
            } else {
                l++;
                r += x;
            }
            q.push(x);
        }
    }

    return 0;
}

H 数羊

大意:

给出n和m的值,求A(n,m):

img

思路:

先暴力打表,然后找出规律即可:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
int const MAXN = 2e5 + 10;
LL n, m, T;

LL qmi(LL a, LL k, LL p) {
    LL res = 1 % p;  // res记录答案, 模上p是为了防止k为0,p为1的特殊情况
    while(k) {  // 只要还有剩下位数
        if (k & 1) res = (LL)res * a % p;  // 判断最后一位是否为1,如果为1就乘上a,模上p, 乘法时可能爆int,所以变成long long
        k >>= 1;  // 右移一位
        a = (LL) a * a % p;  // 当前a等于上一次的a平方,取模,平方时可能爆int,所以变成long long
    }
    return res;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> T;
    while(T--) {
        cin >> n >> m;
        if (n == 1) cout << 2 << endl;
        else if (n == 2) cout << 4 << endl;
        else if (!m) cout << (n + 2) % 998244353 << endl;
        else if (m == 1) cout << n * 2 % 998244353 << endl;
        else cout << 8 * qmi(2, n - 3, 998244353) % 998244353 << endl;
    }
    return 0;
}

I 买花

大意:

n个花,分k天买(k>1,即不能一天全买完),第一天可以买任意朵花,之后每一天买花的数量为前一天的两倍。

问能否在15天内买够n朵花

思路:

设第一天买的花为x个,那么买2天就是买2x+x个,买3天就是买4x+2x+x个...

所以可以枚举买2到15天的情况,也就是枚举能买到x的倍数,然后看n能否整除某个倍数即可

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
int t, n;
int main() {
    cin >> t;
    while (t--) {
        cin >> n;
        int flag = 0;
        for (int i = 2; i <= 15; i++) {
            if (n % ((1 << i) - 1) == 0) {
                flag = 1;
            }
        }
        if (flag) cout << "YE5" << endl;
        else
            cout << "N0" << endl;
    }
    return 0;
}

J 这是一题简单的模拟

大意:

从0号点出发到n个城市,然后返回0号点

现在给出所有的路径,以及k个方案

问花费最少的方案的花费是多少

思路:

直接模拟即可...

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
int const MAXN = 3e2 + 10;
int n, m, k;
int g[MAXN][MAXN];
unordered_map<int, int> mp;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n >> m;
    memset(g, -1, sizeof g);
    for (int i = 1, a, b, c; i <= m; ++i) {
        cin >> a >> b >> c;
        g[a][b] = g[b][a] = c;
    }
    cin >> k;
    LL res = 1e18;
    while(k--) {
        int t;
        cin >> t;
        int curpos = 0;
        LL tmp = 0, flg = 1;
        mp.clear();
        for (int i = 1, p; i <= t; ++i) {
            mp[curpos]++;
            // cout << "cur: " << curpos << endl;
            cin >> p;
            if (g[curpos][p] != -1) {
                tmp += g[curpos][p];
                curpos = p;
            }
            else {
                flg = 0;
            }
        }
        mp[curpos]++;
        if (g[curpos][0]) tmp += g[curpos][0];
        else flg = 0;
        for (int i = 1; i <= n; ++i) if (mp[i] != 1) {
            flg = 0;
            // cout << "ev: " << i << endl;
        }
        if (flg) {
            res = min(res, (LL)tmp);
        }
    }
    if (res != 1e18) cout << res << endl;
    else cout << -1 << endl;
    return 0;
}

K 黑洞密码

大意:

输入一个字符串,然后进行如下操作:

1.确定讯息的长度为32;

2.字符串中第(4n+1sim4n+4)的字母和第(4n+1sim4n+4)的数字为一组,共4组;

3.每组的第1,2,3,4个字符分别往后推每组第1,2,3,4个数字个数 例:如第一个字母为a,第一个数字为3,转换后变为d,'z'之后是'B','Z'之后是'b';

4.将每组内部字母的顺序颠倒;

5.将四组字符合并就是最后的讯息。

思路:

直接模拟,但是需要注意的是,题目中说了z如果往后移动1位那么会变为B,Z移动一位会变为b,比较坑

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
string s;
char ch[50], num[50];
string biao =
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int main() {
    cin >> s;
    int cnt1 = 0, cnt2 = 0;
    for (int i = 0; i < s.size(); i++) {
        if (s[i] >= '0' && s[i] <= '9')
            num[++cnt1] = s[i];
        else
            ch[++cnt2] = s[i];
    }
    string res = "";
    for (int i = 0; i <= 3; i++) {
        string temp = "";
        for (int j = 1; j <= 4; j++) {
            char now;
            if(ch[i * 4 + j]>='a'&&ch[i * 4 + j]<='z'){
                now = biao[ch[i * 4 + j]-'a' + num[i * 4 + j] - '0'];
                if (now >= 'A' && now <= 'Z') now++;
            }
            else {
                now = biao[ch[i * 4 + j]-'A'+26 + num[i * 4 + j] - '0'];
                if (now >= 'a' && now <= 'z') now++;
            }
            temp.push_back(now);
        }
        //cout << temp << endl;
        reverse(temp.begin(),temp.end());
        res = res + temp;
    }
    cout << res << endl;
    return 0;
}

L 建立火车站

大意:

给出n个城市,在这些城市之间可以建立k个车站,问最远的两个车站的最小值是多少(城市也需要看做车站)

需要注意车站位置必须是整数。

思路:

首先将每个区间的距离扔到优先队列里,然后每次都将队头的元素多加一个车站,然后再扔到优先队列里即可

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<double, double> PII;
int const N = 2e5 + 10;
int n, k;
double a[N];
priority_queue<PII, vector<PII>, less<PII> > q;
int main() {
    cin >> n >> k;
    cin >> a[1];
    for (int i = 2; i <= n; i++) {
        cin >> a[i];
    }
    sort(a + 1, a + 1 + n);
    for (int i = 2; i <= n; i++) {
        q.push({a[i] - a[i - 1], 1});
    }
    while (k--) {
        PII t = q.top();
        double num = t.second;
        double p = t.first * num;
        q.pop();

        q.push({p / (num + 1), num + 1});
    }
    cout << ceil(q.top().first) << endl;
    //printf("%lld
", ceil(q.top().first));
    return 0;
}
原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14351435.html