2021“MINIEYE杯”中国大学生算法设计超级联赛(2)(待修改)

本文解析了多项算法设计赛题,包括三维坐标系中等边三角形计数、构造字典序最小字符串方案数量及复习策略优化等问题,提供了清晰的思路与高效代码实现。

2021“MINIEYE杯”中国大学生算法设计超级联赛(2))

导语

涉及的知识点

思维、

链接:2021“MINIEYE杯”中国大学生算法设计超级联赛(2)

题目

1001

题目大意:在三维坐标系给出一个立方体,判断由整点构成的等边三角形有多少个

思路:通过找规律可以发现边长每加一,可构成的三角形数量增加8×i3,累和即可,用立方的和公式,注意取模,对n需要先取模

https://zhuanlan.zhihu.com/p/260139435在这里插入图片描述
证明链接:自然数立方和公式推导方法汇总

代码

#include <bits/stdc++.h>

using namespace std;
int T;
long long n;
const int Mod=1e9+7;
int main() {
    ios::sync_with_stdio(0),cin.tie(0);
    cin >>T;
    while(T--) {
        cin >>n;
        n%=Mod;
        cout <<2*n%Mod*n%Mod*(n-1)%Mod*(n-1)%Mod<<endl;
    }
    return 0;
}

1003

题目大意:

思路:

代码


1005

题目大意:给出一个字符序列,每次操作只能由序列中抽出一个进行前插或者后插,举个例子,如ABCDE,可以这样构造A->AB->…也可以A->BA->…,判断最后满足字典序最小构造出字符串的方案数量

思路:一道有手就行的签到,居然没写,我是伞兵,最后字典序最小的字符串是唯一的,只需要判断一开始有多少个相同的字符即可,例如AAAABC,第一次操作构造A,第二次,A可以前插和后插,算成了两种方案,之后也是如此,一直到B的时候就定下来了,只能顺序插,总方案数为24-1,详见代码,注意取模

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int Mod=1e9+7;
int T;
char str[121212];
signed main() {
    ios::sync_with_stdio(0),cin.tie(0);
    cin >>T;
    while(T--) {
        int n,ans=0,t=1;
        cin >>n;
        cin >>str;
        for(int i=1; i<n; i++)
            if(str[i]==str[i-1])
                ans++;
            else
                break;
        while(ans--) {
            t<<=1;
            t%=Mod;
        }
        cout <<t<<endl;
    }
    return 0;
}

1007

题目大意:

思路:

代码


1008

题目大意:n( n ≤ 50 n\le 50 n50)门考试,还有t( t ≤ 500 t\le 500 t500)天能复习,有m( m ≤ 15000 m\le 15000 m15000)份能提分的学习资料,可以提升x分( 1 ≤ x ≤ 10 1\le x\le 10 1x10),但需要y天( 1 ≤ y ≤ 10 1\le y \le 10 1y10),试求在不挂至少p科( 0 ≤ p ≤ 3 0\le p\le 3 0p3)的情况下,能够获得的最大分数和

思路:首先对于每门课,使用背包计算出对于当前课,在获得s分的情况下花费的最小开销,使用一个数组f[i,j]记录对于第i个物品当获得分数为j的时候的最小开下,之后合并每门课,使用数组g[i,j,k]表示已经计算完i门课的情况下,花费j天,挂了k门的最大分数,详见代码

代码

#include<bits/stdc++.h>
using namespace std;
int T,n,m,x,y,f[100][1212],g[100][600][10],b[12121],c[12121],t,p;
typedef struct node {
    int id,s,d;
    bool operator<(node a) {
        return id<a.id;
    }
} node;
node e[121212];
int main() {
    ios::sync_with_stdio(0),cin.tie(0);
    //freopen("1.in","r",stdin);
    cin >>T;
    while(T--) {
        cin >>n;
        unordered_map<string,int>U;
        int cnt=0;
        for(int i=1; i<=n; i++) {
            string input;
            cin >>input;
            if(!U[input])//离散化
                U[input]=i;
        }
        cin >>m;
        for(int i=1; i<=m; i++) {
            string input;
            int score,day;
            cin >>input>>score>>day;
            e[i].id=U[input];
            e[i].s=score;
            e[i].d=day;
        }
        cin >>t>>p;
        sort(e+1,e+1+m);//按照编号排序
        int last=1;
        e[m+1].id=0;
        for (int i=0; i<=n; i++)//初始化
            for (int j=0; j<=t; j++)
                for (int k=0; k<=p; k++)
                    g[i][j][k]=-100000000;
        for(int i=1; i<=m; i++) {
            if(e[i].id!=e[i+1].id) {//直到编号不同停止
                int k=0;
                for(int j=last; j<=i; j++)//记录
                    b[++k]=e[j].s,c[k]=e[j].d;
                for(int j=1; j<=100; j++)//初始化为最大值
                    f[e[i].id][j]=510;
                f[e[i].id][0]=0;
                for(int j=1; j<=k; j++)
                    for(int l=100; l>=b[j]; l--)
                        f[e[i].id][l]=min(f[e[i].id][l-b[j]]+c[j],f[e[i].id][l]);
                if(e[i].id==1)//下一个dp的初始化
                    for(int j=0; j<=100; j++)//必须从小到大,nmd,为什么
                        if(j<60)
                            g[1][f[1][j]][1]=j;
                        else
                            g[1][f[1][j]][0]=j;
                last=i+1;//上一个学科的边界
            }
        }
        for(int i=1; i<n; i++)//由于第一个已经算了,直接由当前推之后
            for(int j=0; j<=t; j++)
                for(int k=0; k<=p; k++)
                    if(g[i][j][k]>=0) {//初始化的时候为负数,只有大于等于0才有效
                        for(int l=0; l<=100; l++)
                            if(f[i+1][l]+j<=t) {
                                if(l<60&&k!=p)//k不能等于p,因为不能挂更多的科
                                    g[i+1][j+f[i+1][l]][k+1]=max(g[i+1][j+f[i+1][l]][k+1],g[i][j][k]+l);
                                if(l>=60)//单独判断,不能直接用else
                                    g[i+1][j+f[i+1][l]][k]=max(g[i+1][j+f[i+1][l]][k],g[i][j][k]+l);
                            }
                    }
        int ans=-1;
        for(int i=0; i<=t; i++)
            for(int j=0; j<=p; j++)
                ans=max(ans,g[n][i][j]);//不能直接输出g[n][t][p],有些状态到达不了
        cout <<ans<<endl;
    }
    return 0;
}

1011

题目大意:

思路:

代码


参考文献

暂无

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值