A-A+B Problem_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)
A-A+B Problem
题解:
该题只要找到最大的数,只要将其他数和最大的数相加即可,但是最大的数需要和第二大的数相加;所以我们可以用优先队列储存数组,在用一个普通数组储存输入,枚举数组中的元素,如果枚举到其中一个元素等与优先队列的队头,那么我们就将队头弹出,将新队头+现在的元素,然后再把弹出的队头在加入其中;
#include<bits/stdc++.h>
using namespace std;
int b[200005];
int main(){
int n;
cin>>n;
priority_queue<int,vector<int>>a;
for(int i=1;i<=n;i++){
cin>>b[i];
a.push(b[i]);
}
for(int i=1;i<=n;i++){
if(a.top()!=b[i]){
cout<<b[i]+a.top()<<" ";
}
else {
int y=a.top();
a.pop();
cout<<b[i]+a.top()<<" ";
a.push(y);
}
}
return 0;
}
B-Komorebi的数学课_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)
B-Komorebi
题解:我们举一个例子:n=7时;
7 7 7 7 7 7 7;
此时有7个一相乘;
那么我们两个两个合并;
就变成了:
49 49 49 7;
由此当长度为计数的时候我们用p来储存他多出来的数字;
那么n就变成了49,此时长度从7也变成了3(7/2);
p=7;
现在我们将49合并,此时就变成了2401(49*49);
还剩下一个49,将他存入p中,p就变成了7*49;
现在只剩下一个长度为1的2401;
结束循环,此时将2401*p%(n+2);
当长度大于一时,我们就两两合并相同的元素,如果长度为1,那么必定会有一个元素单出来。
那么我们就把单出来的元素放入p中,最后将长度为一的时候就乘以p;
当然快速幂能更快的解决,我这个好像就是快速幂的思想:
#include<bits/stdc++.h>
using namespace std;
int b[1005];
#define int long long
signed main(){
int n;
cin>>n;
int p=1;
int mod=n+2;
int len=n;
while(len!=1){
int m=(n*n)%mod;
if(len%2==0){
len/=2;
}
else{
p*=n;
len/=2;
p%=mod;
}
n=m;
}
cout<<(n*p+mod)%mod<<endl;
return 0;
}
C-次佛锅_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)
C-次佛锅
map的用法,以及字符串的处理,自己模拟
#include<bits/stdc++.h>
using namespace std;
map<string,int>a;
signed main(){
string s;
string str;
string ne;
int f=0;
getline(cin,s);
for(int i=0;i<s.size();i++){
if(s[i]==' '){
f++;
if(f%2==0){
int n=stoi(ne);
a[str]+=n;
}
else {
str=ne;
}
ne.clear();
}
else {
ne+=s[i];
}
if(i==s.size()-1){
int n=stoi(ne);
a[str]+=n;
}
}
int t;
cin>>t;
while(t--){
string k;
cin>>k;
cout<<a[k]<<endl;
}
return 0;
}
D-Setsuna的K数列_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)
D-Setsuna的K数组
读题:二进制的感觉,此时我们就不是以2为底数了,而是以k为底数,我们先将n转换成二进制;
然后要是二进制的某一位为1,那么加上以k为底的x次幂;即可;
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
int a[2000006];
signed main(){
int n,k;
cin>>n>>k;
int i,j=0;
i=n;
while(i)
{
a[j]=i%2;
i/=2;
j++;
}
int ans=0;
int x=1;
for(i=0;i<=j-1;i++){
if(a[i]==1)ans+=x;
ans%=mod;
x*=k;
x%=mod;
}
cout<<(ans+mod)%mod<<endl;;
}
F-黄金律法_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)
F-黄金律法:
此题只用将a数组中的最大值乘以b数组的最小值即可;
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[100005];
int b[100005];
signed main(){
int t;
cin>>t;
int n;
while(t--){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int j=1;j<=n;j++){
cin>>b[j];
}
sort(a+1,a+1+n);
sort(b+1,b+1+n);
int ans=0;
for(int i=1;i<=n;i++){
ans+=a[i]*b[n-i+1];
}
cout<<ans<<endl;
}
return 0;
}
J-史东薇尔城_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)
J-史东薇尔城
堆优化的Dijkstra算法,因为要从某一点到起点1,然后从1点到另一点,所以最后的答案输出就是
dist[x]+dist[y];
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
vector<PII>mp[150005];
int n,m;
int dist[150001];
bool st[155001];
void djstl(){
for (int i = 1; i <=n ; ++i) {//举例数组初始化为无穷大
dist[i]=(int)1e15;
}
priority_queue<PII,vector<PII>,greater<PII>>q;//定义优先队列
dist[1]=0;//起点的距离是0
q.push({0,1});//将起点放入队列中,要对距离排序,所以距离在第一位
while(!q.empty()){//如果队列不为空
auto t=q.top();//将距离最小的点弹出
q.pop();
int ver=t.second,ds=t.first;//最上面的点标号是ver,距离是ds;
if(st[ver])continue;//如果该点已经确定了最短路,就继续找下一个最近的点
st[ver]= true;//标记
for (int i = 0; i <mp[ver].size() ; ++i){//找以ver为出边所连接的点
auto p=mp[ver][i];//枚举所有他所连接的点;
if(dist[p.first]>ds+p.second){//如果1到该点的距离大于(已经确定最短路的点到该点的距离加上最短路的距离)
dist[p.first]=ds+p.second;//更新该点的最短距离
q.push({dist[p.first],p.first});//将已经找到最短路的点放入队列中;
}
}
}
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;
for (int i = 0; i <m ; ++i) {
int x,y,z;
cin>>x>>y>>z;
mp[x].push_back({y,z});//读入边
mp[y].push_back({x,z});
}
djstl();//进行最短路
int t;
cin>>t;
while(t--){
int a,b;
cin>>a>>b;
cout<<dist[a]+dist[b]<<endl;
}
return 0;
}
L-剪绳子_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)
L-剪绳子
暴力枚举就行,将剪断过的数存入在set里面,让他自动排序,然后每次要求输出数就遍历set知道找到set中的某个元素大于输入的f元素,不然一直更新他的左端点,否则更新右端点f,然后break;
输出两者的差值即可;
#include<bits/stdc++.h>
using namespace std;
#define int long long
set<double>ans;
signed main(){
int t;
cin>>t;
while(t--){
string a;
cin>>a;
double f;
cin>>f;
if(a=="C"){
ans.insert(f);
}
else {
double start=0.0;
double endd=10.0;
for(auto p:ans){
if(p>f){
endd=p;
break;
}
start=p;
}
printf("%.5f\n",endd-start);
}
}
return 0;
}
H-叠硬币_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com
H-叠硬币
01背包,动态规划;
dp[i]中储存的是高度为i的最小堆数是多少;
01背包的思路:
当他可以装 j 体积的东西时,也就是当高度为j时,比较高度为j-a[i]时在加上本省自己的堆数时,谁的堆数最小;
最后输出答案时,因为要求输出字典序最小,所以我们就从数组i开始枚举,如果要求的减去目前这堆的高度后的堆数等于答案的堆数减一,就说明你是其中一个答案,输出就行,那么要求的高度就要更新为减去这堆高度的高度;因为h是根据前面的高度堆数累加上来的。所以一定存在,如果当堆数满足要求时,后面就一定存在与该堆数匹配最后高度为h的堆数;
说的要点乱,看代码注释吧;
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int arr[N];
int dp[N];
int main(){
int n,h;
cin>>n>>h;
for(int i=1;i<=n;i++){
cin>>arr[i];
}
sort(arr+1,arr+1+n);//对数组从小到大排序
memset(dp,0x3f,sizeof dp);//求最小值 赋值最大
dp[0]=0;//边界条件
for(int i=1;i<=n;i++){
for(int j=h;j>=arr[i];j--){//滚动数组中的第二层循环要从大到小,防止他更新的是i,
//实质上他更新的是i-1;
dp[j]=min(dp[j],dp[j-arr[i]]+1);//高度为h的最小堆数
//体积为arr[i],权重为他的堆数——1堆
}
}
//如果高度为h,且他没有被更新过
if(dp[h]==0x3f3f3f3f)cout<<"-1\n";
else {
cout<<dp[h]<<"\n";//最少有几堆
int p=dp[h];
p--;
for(int i=1;i<=n;i++){//枚举数组中的堆数
if(dp[h-arr[i]]==p){//高度减去(某一堆)的高度剩下的堆数最少有几堆;
cout<<arr[i]<<" ";//输出该数组
h-=arr[i];//将高度减去这一堆的高度
p--;//堆数减减
}
}
}
return 0;
}
G-天气预报_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)
G-天气预报:
用两个指针:
对于一个01字符串,要找到有几个区间满足0数量和1的数量分别不小于a和b
它是有单调性:当右边界满足的时候,后面的也一定满足,所以答案直接加上n-左边界,剩下的右边界就都是答案。
故可以双指针来维护,需要注意的是 a==0 b==0
这种情况,还需额外加1。因为题目说了可以啥都不选
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a,b,sum;
int l,r;
int x,y;
int q,p;
signed main()
{
cin>>n>>a>>b;
string s;
cin>>s;
int ans=0;
for(int i=0,j=0;i<s.size();i++)
{
if(s[i]=='1')y++;
else x++;
while(x>=a&&y>=b&&j<=i)
{
ans+=n-i;
if(s[j]=='0')x--;
else y--;
j++;
}
}
if(a+b==0)cout<<ans+1;
else cout<<ans;
return 0;
}
E-Wiki下象棋_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)
E—Wiki下象棋:
E-Wiki下象棋_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)
第一个bfs1是国际象棋的做法,第二个bfs2是中国国旗的做法
国际象棋的走法是:
每一步只可以水平或垂直移动一点,再按对角线方面向左或者右移动(另一种解释,可以先在水平/竖直方向走两格,然后在竖直/水平方向走一格)。另外,马不允许跳出界外,也即必须跳完一步之后仍在棋盘上。
中国象棋的走法:
在没有障碍物的情况下,其走法与国际象棋一样。唯一不同的是,如果马走了一格就遇到障碍物,马就不能继续向这个方向前进了(又称为"马脚")。
题目中,国际象棋是没有障碍物的;
所以可以直接按照马走的日字格宽度优先搜索;
中国象棋中有马脚,所以在每一次走日字格的时候要判断所谓的马脚是否存在;
如果存在就跳过这个日,循环找别的日字;
#include<bits/stdc++.h>
using namespace std;
const int N=300+9,M=N*N+9;
int mp[N][N];
int n,m,k,a,b,c,d;
int ans1,ans2;
int vis[N][N];
struct node {
int x,y,step;
};
int dx[]={-1,-2,-2,-1,1,2,2,1};
int dy[]={-2,-1,1,2,2,1,-1,-2};
int bfs1(){
queue<node>q;
while(q.size())q.pop();
q.push({a,b,0});
vis[a][b]=1;
if(a==c&&b==d)return 0;
while(q.size()){
auto p=q.front();
q.pop();
for(int i=0;i<8;i++){
int nx=dx[i]+p.x,ny=dy[i]+p.y;
if(nx<1||nx>n||ny<1||ny>m)continue;
if(vis[nx][ny])continue;
if(mp[nx][ny]==-1)continue;
vis[nx][ny]=1;
if(nx==c&&ny==d){
return p.step+1;
}
q.push({nx,ny,p.step+1});
}
}
return -1;
}
int nox[]={0,-1,-1,0,0,1,1,0};
int noy[]={-1,0,0,1,1,0,0,-1};
int bfs2(){
queue<node>q;
while(q.size())q.pop();
q.push({a,b,0});
vis[a][b]=1;
if(a==c&&b==d)return 0;
while(q.size()){
auto p=q.front();
q.pop();
for(int i=0;i<8;i++){
int nx=dx[i]+p.x,ny=dy[i]+p.y;
int nnx=p.x+nox[i],nny=p.y+noy[i];
if(nx<1||nx>n||ny<1||ny>m)continue;
if(mp[nx][ny]==-1)continue;
if(mp[nnx][nny]==-1)continue;
if(vis[nx][ny])continue;
vis[nx][ny]=1;
if(nx==c&&ny==d){
return p.step+1;
}
q.push({nx,ny,p.step+1});
}
}
return -1;
}
int main(){
std::ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T;
cin>>T;
while(T--){
memset(vis,0,sizeof vis);
ans1=ans2=0;
cin>>n>>m>>k>>a>>b>>c>>d;
memset(mp,0,sizeof mp);//!!
while(k--){
int x,y;
cin>>x>>y;
mp[x][y]=-1;
}
// cout<<"---"<<endl;
cout<<bfs1()<<" ";
memset(vis,0,sizeof vis);
cout<< bfs2()<<"\n";
}
return 0;
}
“夏天一闪而过
还好我们常常见面 \( ̄︶ ̄)/”