导语
涉及的知识点
思维、
链接: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 n≤50)门考试,还有t( t ≤ 500 t\le 500 t≤500)天能复习,有m( m ≤ 15000 m\le 15000 m≤15000)份能提分的学习资料,可以提升x分( 1 ≤ x ≤ 10 1\le x\le 10 1≤x≤10),但需要y天( 1 ≤ y ≤ 10 1\le y \le 10 1≤y≤10),试求在不挂至少p科( 0 ≤ p ≤ 3 0\le p\le 3 0≤p≤3)的情况下,能够获得的最大分数和
思路:首先对于每门课,使用背包计算出对于当前课,在获得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
题目大意:
思路:
代码
参考文献
暂无
本文解析了多项算法设计赛题,包括三维坐标系中等边三角形计数、构造字典序最小字符串方案数量及复习策略优化等问题,提供了清晰的思路与高效代码实现。

被折叠的 条评论
为什么被折叠?



