2023年湖南工学院暑期集训第二次周测

文章包含一系列编程挑战,涉及数学和逻辑推理。例如,从钞票堆中选取特定乘积的组合,奇偶性卡牌游戏的胜者预测,链表操作模拟,矩阵元素定位,圆环滚动轨迹计算以及不重复分配冰棍的问题。挑战要求参赛者运用最优策略和算法设计来解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拐咯拐咯,又是被爆揍的一天 

目录

7-1 Enchanted

输入格式:

输出格式:

输入样例 1:

输出样例 1:

样例解释 1:

输入样例 2:

输出样例 2:

样例解释 2:

输入样例 3:

输出样例 3:

样例解释 3:

7-2 How long could we be a sad song 

输入格式:

输出格式:

输入样例 1:

输出样例 1:

样例 1 解释:第一轮 kk 先选 233 和 2333 做乘法,得到 543589;此时牌堆剩下 23333 和 543589,第二轮轮到 mz 操作,他选择将剩下两个数做加法,则得到 566922 为偶数;此时牌堆剩下 566922,第三轮轮到 kk 操作,牌堆只剩一张牌,因此游戏结束,最后一张牌为偶数,mz 胜利。上述所描述的只是其中一种方案,其他的方案大家可以自行尝试。但无论怎样选择操作,无论 kk 如何努力,mz 都能将最后一个数变成偶数。

注意:上述例子中,当剩下 23333 和 543589 时,如果 mz 选择了乘法,最终得数将变成奇数,他将失去胜利,因此为了自己能够获得胜利,mz 一定会选择加法。

输入样例 2:

输出样例 2:

7-3 Amazing News 

输入格式:

输出格式:

数据范围:

输入样例:

输出样例:

7-4 Counter-diagonal 

输入格式:

输出格式:

输入样例 1:

输出样例 1:

输入样例 2:

输出样例 2:

7-5 扭转乾坤 

题解

本题为判题方式为 Special Judge

输入格式:

输出格式:

输入样例:

输出样例:

7-6 分冰棍 

输入格式:

输出格式:

数据范围:

输入样例:

输出样例:


7-1 Enchanted

众所周知,7 月 7 号 Taylor Swift 发布了 《SPEAK NOW》(Taylor’s Version),kk 作为一个霉粉,他现在想托朋友为他买一张实体CD,而他的朋友没有那么轻易的就答应他,而是给了他一个问题,只有当 kk 解决掉这个问题之后才能获得实体CD。但是呢,kk 现在没有空去解决这个问题,那么,善良的你一定会帮他解决这个问题并帮助他拿到他心爱的专辑的吧!!

 

 

这个问题是这样的, kk 有 n 堆钞票,其中每堆钞票的钞票数量为 Si​,我们记第 i 堆中的第 j 张钞票的价值为 ai,j​。现在 kk 有一个总乘积 x。我们需要从每堆里选出一张钞票,请问一共有多少种方案,使得这些钞票的价值乘积恰好为 x。

 

注意:当选择的钞票价值相同,但编号不同时,我们认为是不同的方案。例如,某一堆的两个相同价值的球被记为两种方案。


提示:可以从数据范围以及累乘符号入手。

 

输入格式:

第一行输入两个正整数 n(2≤n) 和 x(1≤x≤1018)。分别代表钞票堆数和总乘积。注意:数据保证每堆钞票数量的乘积最多为 105:∏i=1n​Si​≤105。

 

接下来 n 行,每行先输入一个整数 Si​(2≤Si​)。代表第 i 堆钞票数量。再输入 Si​ 个 整数 ai,j​(1≤ai,j​≤109,1≤j≤Si​)。代表每张钞票的价值,某堆可能会出现相同价值钞票。

 

输出格式:

输出方案数

 

输入样例 1:

2 40
3 1 8 4
2 10 5

输出样例 1:

2

样例解释 1:

对于样例 1,当在第 1 堆中选择钞票 3 和 第 2 堆中选择钞票 1 时,我们有 a1,3​×a2,1​=4×10=40。当在第 1 堆中选择钞票 2 和 第 2 堆中选择钞票 2 时,我们有 a1,2​×a2,2​=8×5=40。没有其他方法可以使乘积为 40,所以答案是 2。

输入样例 2:

3 200
3 10 10 10
3 10 10 10
5 2 2 2 2 2

输出样例 2:

45

样例解释 2:

对于样例 2,请注意,我们区分所有钞票,即使它们有相同的价值。

输入样例 3:

3 1000000000000000000
2 1000000000 1000000000
2 1000000000 1000000000
2 1000000000 1000000000

输出样例 3:

0

样例解释 3:

对于样例 3,没有方法使乘积为 x。

一个dfs的题趴,赛时答案错误,写的是乘法没有考虑到爆longlong的情况 

 除法版本

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll x;
vector<ll>v[100005];
ll cnt;
int n;
void dfs(ll a, ll c) {//a表示层数,c表示被除数
    if (a == n) {//当到最后一层时
        if (c == 1) {//如果被除数等于1,表示找到一种方案数
            cnt++;
        }
        return;
    }
    for (int i = 0; i < v[a].size(); i++) {
        ll t = v[a][i];
        if(c%t==0){//判断是否整除
            dfs(a + 1, c /t);
        }
    }
}
int main() {
    cin >> n >> x;
    for (int i = 0; i < n; i++) {
        ll q;
        cin >> q;
        while (q--) {
            ll p;
            cin >> p;
            v[i].push_back(p);
        }
    }
    dfs(0, x);
    cout << cnt<<"\n";
    return 0;
}

乘法版本

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll x;
vector<ll>v[100005];
ll cnt;
int n;
void dfs(ll a, ll c) {//a表示层数,c表示乘数
    if (a == n) {//到最后一层
        if (c == x) {//正好等于x时,表示找到一个合理的方案数
            cnt++;
        }
        return;
    }
    for (int i = 0; i < v[a].size(); i++) {
        ll t = v[a][i];
        if (x/t>=c&&x%t==0) {//判断是否整除和是否会爆longlong
            dfs(a + 1, c * t);
        }
    }
}
int main() {
    cin >> n >> x;
    for (int i = 0; i < n; i++) {
        ll q;
        cin >> q;
        while (q--) {
            ll p;
            cin >> p;
            v[i].push_back(p);
        }
    }
    dfs(0, 1);
    cout << cnt<<"\n";
    return 0;
}

7-2 How long could we be a sad song 

5 月 26 号 Taylor 正式发售 《Midnights》 的深夜豪华版(The Late Night Version),其中包含了一首 CD 独占曲 You’re Losing Me,kk 听的非常上头,于是边听边跟 mz 玩起了小游戏。

这个游戏是这个亚子的,他们会拿出 n 张卡牌,然后在每张卡牌上用铅笔写上一个正整数。
游戏由 kk 先手操作。对于每次操作:

  • 1.若当前只剩下一张卡牌时,游戏结束,卡牌上的数字为偶数则 mz 获胜,否则 kk 获胜。
  • 2.若当前剩余两张牌及以上,则当前玩家可以任选两张卡牌,假设这两张牌的值为 a,b,当前玩家可以对这两张牌选择乘法或者加法得到一个新的值 c,然后将其中一张卡牌丢掉,另一张卡牌的原数字擦掉并改写为 c 放入卡牌堆。

现在假设双方 均以最优策略(大家都尽自己最大的努力去获得胜利) 操作,最后谁会赢?

 

输入格式:

第一行输入一个整数 n(1≤n≤106),代表最初的卡牌数。
第二行输入 n 个整数 ai​(1≤ai​≤109),代表卡牌的值。

 

输出格式:

游戏结束,卡牌上的数字为偶数则输出 mz nb,否则输出 kk caiji。

 

输入样例 1:

3
233 2333 23333

输出样例 1:

mz nb
样例 1 解释:第一轮 kk 先选 233 和 2333 做乘法,得到 543589;此时牌堆剩下 23333 和 543589,第二轮轮到 mz 操作,他选择将剩下两个数做加法,则得到 566922 为偶数;此时牌堆剩下 566922,第三轮轮到 kk 操作,牌堆只剩一张牌,因此游戏结束,最后一张牌为偶数,mz 胜利。上述所描述的只是其中一种方案,其他的方案大家可以自行尝试。但无论怎样选择操作,无论 kk 如何努力,mz 都能将最后一个数变成偶数。
注意:上述例子中,当剩下 23333 和 543589 时,如果 mz 选择了乘法,最终得数将变成奇数,他将失去胜利,因此为了自己能够获得胜利,mz 一定会选择加法。
 

输入样例 2:

4
1 1 1 1

输出样例 2:

kk caiji

就是这个又熟悉又猛wa的题搞烂了我的心态,小菜是这样的

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n;
ll cnt;
int main() {
    cin>>n;
    for(int i=0;i<n;i++){
        ll x;
        cin>>x;
        if(x%2!=0)cnt++;//记录奇数的个数
    }
    if(n==1||n==2){//如果n==1||n==2时,只要出现过奇数,kk赢,反之mz赢
        if(cnt)cout<<"kk caiji\n";
        else cout<<"mz nb\n";
    }
    else if(n%2==0){//对于偶数,只有当奇数个数超过n-2时kk才能赢,反之mz赢
        if(cnt>=n-2)cout<<"kk caiji\n";
        else cout<<"mz nb\n";
    }
    else{//奇数mz赢
        cout<<"mz nb\n";
    }
    return 0;
}

7-3 Amazing News 

好消息,好消息,7月14-7月16薛之谦!他来衡阳开演唱会啦!!!!!!!!mq想拜托他的朋友帮他抢到一张物美价廉的原价外场票,然而他的朋友正忙着解决一个大问题没有时间帮mq抢票。如果mq帮助朋友解决了这个问题就可以获得老薛的演唱会门票,但是mq又解决不了这个问题,那么善良的你一定会帮助mq解决问题助他拿到演唱会门票的吧!!!一定会的吧/(ㄒoㄒ)/~~

 

在演唱会中由于每个人有各自的座位,演唱会的入口大小只能让一个人通过,朋友便想通过让观众排队的方式让他们有序入场,提高进场效率

一共有N个人购买了演唱会门票,每个人有个编号:1,2,3…N

每个座位只能坐一个人

编号不等同座位号,每个人的座位号只有朋友通过后台数据才知道

朋友已经提前计算好了每个人在队伍中的位置,你只需要跟着朋友的指示将最后的队伍输出就可以了:

  • 1 x y: 将y排到x的后面
    需要遵守以下约定

    • x=y;

    • 在本次操作之前没有任何人排在x后面;

    • 在本次操作之前没有任何人排在y前面;

    • 在本次操作之前,x和y在不同的队伍中;

  • 2 x y: 将x,y断开
    需要遵守以下约定

    • x=y;

    • 在本次操作之前y正好排在x的后面;

  • 3 x: 按顺序从头到尾打印出x所在的队伍目前的排队情况

(题目不特指薛之谦演唱会,情节纯属虚构,如有雷同纯属巧合)

输入格式:

第一行输入两个整数:人数N,朋友所需操作数Q
接下来Q行每行输入2到3个数,第一个数为操作pi​,后面的1或2个数为人员x,y

输出格式:

如果pi​=3,输出一行第一位数字为该队伍目前的人数,后面j1​,j2​,j3​…jm​表示该队伍人员

数据范围:

  • 2≤N≤105

  • 1≤Q≤105

  • 1≤x≤N

  • 1≤y≤N

  • 所有输入都是正整数

  • 所有的操作都符合条件

  • 所有打印的最大长度不会超过106

输入样例:

在这里给出一组输入。例如:

7 14
1 6 3
1 4 1
1 5 2
1 2 7
1 3 5
3 2
3 4
3 6
2 3 5
2 4 1
1 1 5
3 2
3 4
3 6

输出样例:

在这里给出相应的输出。例如:

5 6 3 5 2 7
2 4 1
5 6 3 5 2 7
4 1 5 2 7
1 4
2 6 3

链表题,按题意模拟即可

#include <bits/stdc++.h>
using namespace std;
int n, q, cnt;
int a[100005];//前面的
int b[100005];//后面的
int c[100005];
int main() {
    cin >> n >> q;
    while (q--) {
        int p;
        cin >> p;
        if (p == 1) {
            int x, y;
            cin >> x >> y;
            a[y] = x;//y前标记为x
            b[x] = y;//x后标记为y
        }
        else if (p == 2) {
            int x, y;
            cin >> x >> y;
            a[y] = 0;//断开则归0
            b[x] = 0;//断开则归0
        }
        else {
            int x;
            cin >> x;
            while (a[x] != 0) {//往前找到链表首元素
                x = a[x];
            }
            cnt = 0;
            while (b[x] != 0) {//往后找到链表末尾元素
                c[cnt++] = x;
                x = b[x];
            }
            c[cnt++]=x;
            cout << cnt << " ";//按要求输出
            for (int i = 0; i < cnt; i++) {
                cout << c[i];
                if(i!=cnt-1)cout<< ' ';
            }
            cout << "\n";
        }
    }
    return 0;
}

7-4 Counter-diagonal 

给定一个 n∗n 的方阵,行和列的下标均从 0 开始 ,该方阵仅由数字组成。而你的任务是求出方阵中 x,y 位置上所对应的数字,其中 x 代表行,y 代表列。

下图所示分别为一个 3∗3 的方阵,和一个 5∗5 的方阵,请根据该方阵的规律推出其他大小方阵排列规律。

 

输入格式:

输入三个整数 n(1≤n≤109+1),x(0≤x≤109),y(0≤y≤109)

输出格式:

输出该位置对应的数值。

输入样例 1:

3 2 1

输出样例 1:

7

输入样例 2:

5 2 2

输出样例 2:

12

手推公式题,找规律 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,x,y;
int main(){
    cin>>n>>x>>y;
    // n=3;
    // for(int x=0;x<n;x++){
    //     for(int y=0;y<n;y++){
    ll ans=((x+2)*(x+1)/2-1);//对应的列的首行元素
    if(y<n-x){//如果y小于这个范围
        ans+=y*(x+1)+(y*(y-1))/2;//当前列是从x+1一直加到y的公差为1的等差数列
    }
    else{//反之
        ans+=((n-1)-x)*(x+1)+((n-1)-x)*((n-1)-x-1)/2;
        //前面是当前列从x+1到(n-1)的公差为1的等差数列
        int t=y-((n-1)-x);//剩下的行数
        ans+=t*(n-1)-t*(t-1)/2;//遵循从(n-1)开始公差为-1的等差公式
    }
    cout<<ans;
    //         cout<<' ';
    // }cout<<"\n";
    // }
    return 0;
}

7-5 扭转乾坤 

题解

自己比划一下可以发现轨迹是一条直线,长度为 4∗n∗d,唯一的坑点是注意爆 longlong。

本题为判题方式为 Special Judge

 

你现在有两个圆环,其中小圆环的直径为 d,大圆环的直径是 2d。你将小圆环防在大圆环内,并让小圆环紧贴大圆环内壁进行无滑动的滚动。

你总是喜欢动态的美,你在小圆环上等间隔地标记了 n 个点,你想知道在小圆环贴着大圆环运动一周后,你所标记的 n 个点所经过的轨迹的长度之和是多少。

输入格式:

输入包含一行,两个整数 n,d(1≤n,d≤109)。

输出格式:

输出包含一行一个浮点数,表示 n 个点所经过的轨迹的长度之和,所输出的答案和标准答案的绝对误差或相对误差在 10−6 范围内会被认为是正确的。

输入样例:

1 1

输出样例:

4.00000000

这个题确实不知道为啥,盲猜了一发4nd过了

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const double PI=3.141592635;
int main() {
    ll n,d;
    cin>>n>>d;
    printf("%.8f",4*n*d*1.0);
    return 0;
}

7-6 分冰棍 

衡阳太热啦,mq为了避暑进货一大批冰棍,现在mq决定让大家帮忙分冰棍,并把冰棍奖励给榜一

现在一共有N根冰棍和M个人,你需要把冰棍分给每个人,并且使每个人所分到的冰棍数都不一样(没有任何两个人的冰棍数是一样的)如果可以这样分输出"possible",否则输出"impossible"。

输入格式:

第一行一个正整数T

接下来T行每行两个数字N,M表示冰棍数和人数;

输出格式:

共T行每行输出"possible"或者"impossible"。

数据范围:

  • 1≤T≤5
  • 1≤N≤1000000
  • 1≤M≤1000

输入样例:

在这里给出一组输入。例如:

3
9 3
12 1
9 4

输出样例:

在这里给出相应的输出。例如:

possible
possible
impossible

题目等价于判断首项为1,公差为1的等差公式和冰棍数的大小,一开始把公式整错了尬住

#include <bits/stdc++.h>
using namespace std;
int main() {
    int t;
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        if(m*(m+1)/2<=n){
            cout<<"possible\n";
        }
        else cout<<"impossible\n";
    }
    return 0;
}

 

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值