1.Ltree的数据结构
T322022 Ltree的数据结构 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
主次关键字的排序
用结构体
比赛过程中,其它都很顺利,问题出在了名次上,一直找不到错误点,满分25分,只对了一个测试点,拿了两分,其它都是RE
比赛代码(错误):
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
const int N=10010;
LL n,m,k;
struct Stu{string s;int x;bool operator<(const Stu &W)const{if(x!=W.x) return x>W.x;return s<W.s;}
}q[N];
int idx[N];
LL sum;
int p;
int main()
{cin>>n>>m>>k;for(int i=0;i<n;i++){cin>>q[i].s>>q[i].x;if(q[i].x>=60&&q[i].x<m) sum+=20;if(q[i].x>=m&&q[i].x<=100) sum+=50;}sort(q,q+n);idx[0]=1;LL cnt=1;for(int i=1;;i++){cnt++;if(q[i].x==q[i-1].x){idx[i]=idx[i-1];}else{idx[i]=cnt;}if(idx[i]==k){p=i;break;}}LL cnt2=0;for(int i=p+1;;i++){if(q[i].x==q[p].x){idx[i]=k;}else break;cnt2++;}printf("%lld\n",sum);for(int i=0;i<=p+cnt2;i++){cout<<idx[i]<<" "<<q[i].s<<" "<<q[i].x<<endl;}return 0;
}
当时想的是用idx[i]记录i的名次,然后先一直算到名次为k的i,后面再加上分数与名次为k的相同的
问题一:尽量不要在循环的括号里写;;,尽量有个范围,虽然后面满足某条件时可以break,但是如果没有考虑周全,漏掉了某些情况,那么就会死循环
问题二:idx不一定能等于k,如找名次前二的,90 90 80 名次为1 1 3,就没有名次二
总之漏洞很多
赛后进行一个修改:算名次的那个循环就专门算名次,把n个数的名次都算出来,不做其它事情
另外一个循环,就算名次小于等于k的有几个
这样,分工明确,思路清晰
一个循环只做一件事情,不容易出错
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
const int N=10010;
LL n,m,k;
struct Stu{string s;int x;bool operator<(const Stu &W)const{if(x!=W.x) return x>W.x;return s<W.s;}
}q[N];
int idx[N];
LL sum;
int p;
int main()
{cin>>n>>m>>k;for(int i=0;i<n;i++){cin>>q[i].s>>q[i].x;if(q[i].x>=60&&q[i].x<m) sum+=20;if(q[i].x>=m&&q[i].x<=100) sum+=50;}sort(q,q+n);idx[0]=1;LL cnt=1;for(int i=1;i<n;i++){cnt++;if(q[i].x==q[i-1].x) idx[i]=idx[i-1];else idx[i]=cnt;}int p=0;for(int i=0;i<n;i++){p++;if(idx[i]>k&&idx[i-1]<=k){break;}}printf("%lld\n",sum);for(int i=0;i<p-1;i++){cout<<idx[i]<<" "<<q[i].s<<" "<<q[i].x<<endl;}return 0;
}
2.乘法口诀
T322026 乘法口诀 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
比赛代码(20分拿了14分)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=1010;
int a[N];
int n;
int main()
{int cnt=2;cin>>a[1]>>a[2];cin>>n;int cnt3=cnt;
// printf("%d %d %d\n",a[1],a[2],a[3]);while(cnt3<=n){int x=a[cnt]*a[cnt-1];
// printf("%d\n",x);int cnt1=0;int t=x;while(t){t/=10;cnt1++;}
// printf("%d\n",cnt1);int cnt2=cnt1;
// printf("%d ",cnt2);while(x){int y=x%10;a[cnt3+cnt2]=y;
// printf("%d %d \n",cnt+cnt2,y);cnt2--;x/=10;}cnt3=cnt3+cnt1;cnt++;}
// printf("%d %d %d\n",a[1],a[2],a[3]);for(int i=1;i<=n;i++) printf("%d ",a[i]);return 0;
}
加了很多注释是因为当时有点小错误,找不到,就输出数来检验,另外,用纸笔模拟全过程也不失为一种检验的好方法
问题一:题目中数列最后两个数相乘得到一个新数,最后两个指的是
1 2,2 3,3 4,4 5,以此类推,根据样例才搞懂题意
问题二:每一位都成为数列的一项,那么数列的每一项只能是0到9,所以相乘最多是两位数,也就是说只要讨论两种情况,相乘是一位数或者两位数,比赛中我用while计算有多少位,使得题目更复杂了
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=1010;
int a[N];
int n;
int main()
{int cnt=2;cin>>a[1]>>a[2];cin>>n;int cnt1=cnt;while(cnt1<=n){int x=a[cnt]*a[cnt-1];if(x<10){a[++cnt1]=x;}else{int y=x%10;x/=10;a[++cnt1]=x;a[++cnt1]=y;}cnt++;}for(int i=1;i<=n;i++) printf("%d ",a[i]);return 0;
}
3.双人成行中的小游戏
T322070 双人成行中的小游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
记录每一行每一列的反转次数,遍历所有灯泡,该灯泡所在行列反转次数之和为奇数则亮
题目中H*W<=5*1e6,这样的话不知道行列具体数,可能行5*1e6,列为1,也可能行为1,列为5*1e6,这样定义二维数组都不好定义,要么用动态数组
但是反转的话,转过去又转回来,往返,那么就与奇数次偶数次有关了
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=5e6+10;
int a[N],b[N];//a[i]记录i行反转的次数,b[j]记录j列反转的次数
int main()
{int h,w,k;cin>>h>>w>>k;while(k--){int n,m;cin>>n>>m;if(n==1){a[m]++;}else b[m]++;}LL res=0;for(int i=1;i<=h;i++){for(int j=1;j<=w;j++){if((a[i]+b[j])%2==1) res++;}}cout<<res<<endl;return 0;
}
4.顶级理解
错误代码(25分拿了8分):
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1010;
int a[N];
int sum;
int main()
{int u,v,n;cin>>u>>v>>n;int cnt=1;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++){sum+=a[i];if(sum-u>=0){cout<<"Yes "<<v<<endl;break;}if(sum/100==cnt&&i>=3){v-=(a[i]+a[i-1]+a[i-2]);cnt++;}if(sum/100==cnt&&i==2){v-=(a[2]+a[1]);cnt++;}if(v<=0){cout<<"gg "<<u-sum<<endl;break;}}if(v>0&&u-sum>0) cout<<"No "<<u-sum<<endl;return 0;
}
注意,boss会遗忘三次招式,也就意味这三次招式要出栈
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;
const int N=1010;
int a[N];
int sum;
int main()
{int u,v,n;cin>>u>>v>>n;int cnt=1;stack<int>q;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++){q.push(a[i]);sum+=a[i];if(sum-u>=0){cout<<"Yes "<<v<<endl;break;}if(sum/100==cnt){if(q.size()){v-=q.top();q.pop();}if(q.size()){v-=q.top();q.pop();}if(q.size()){v-=q.top();q.pop();}cnt++;}if(v<=0){cout<<"gg "<<u-sum<<endl;break;}}if(v>0&&u-sum>0) cout<<"No "<<u-sum<<endl;return 0;
}
5.wyb爱旅行
思路:初看题目,想到最短路,但是题目多加了一个条件,就是在途中要打一次codeforces,这样的话,原本路径最短的加上了一次网费,就不一定是最小的了
做法是用两次最短路,求从1到其它点的最短路以及从n到其它点的最短路。枚举每个城市,从1到该城市的最短距离加上该城市到n的最短距离,再加上该城市的网费,取最小的
错误代码(只对了一个样例):
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
typedef long long LL;
const int N=100010,M=2*N;
int p[N];
int n,m;
int h[N],e[M],w[M],ne[M],idx;
int dist[N],d[N];
bool st[N],s[N];
void add(int a,int b,int c){e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1]=0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,1});
while(heap.size()){
auto t=heap.top();
heap.pop();
int ver=t.second,distance=t.first;
if(st[ver]) continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>distance+w[i]){
dist[j]=distance+w[i];
heap.push({dist[j],j});
}
}
}
}
void dijkstra1(){
memset(d,0x3f,sizeof d);
d[n]=0;
priority_queue<PII,vector<PII>,greater<PII>>q;
q.push({0,n});
while(q.size()){
auto t=q.top();
q.pop();
int ver=t.second,distance=t.first;
if(s[ver]) continue;
s[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i]){
int j=e[i];
if(d[j]>distance+w[i]){
d[j]=distance+w[i];
q.push({d[j],j});
}
}
}
}
int main()
{cin>>n;memset(h,-1,sizeof h);for(int i=1;i<=n;i++) cin>>p[i];cin>>m;while(m--){int u,v,c;cin>>u>>v>>c;add(u,v,c);add(v,u,c);}dijkstra();dijkstra1();int min1=dist[1]+d[1]+p[1];for(int i=2;i<=n;i++){min1=min(min1,dist[i]+d[i]+p[i]);}cout<<min1<<endl;return 0;
}
错误原因是要建两个图,直接改无向边可能会有更短的路出现
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
typedef long long LL;
const int N=100010,M=2*N;
int p[N];
int n,m;
int h[N],e[M],w[M],ne[M],idx;
int h1[N],e1[M],w1[M],ne1[M],idx1;
int dist[N],d[N];
bool st[N],s[N];
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void add1(int a,int b,int c){
e1[idx1]=b,w1[idx1]=c,ne1[idx1]=h1[a],h1[a]=idx1++;
}
void dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1]=0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,1});
while(heap.size()){
auto t=heap.top();
heap.pop();
int ver=t.second,distance=t.first;
if(st[ver]) continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>distance+w[i]){
dist[j]=distance+w[i];
heap.push({dist[j],j});
}
}
}
}
void dijkstra1(){
memset(d,0x3f,sizeof d);
d[n]=0;
priority_queue<PII,vector<PII>,greater<PII>>q;
q.push({0,n});
while(q.size()){
auto t=q.top();
q.pop();
int ver=t.second,distance=t.first;
if(s[ver]) continue;
s[ver]=true;
for(int i=h1[ver];i!=-1;i=ne1[i]){
int j=e1[i];
if(d[j]>distance+w1[i]){
d[j]=distance+w1[i];
q.push({d[j],j});
}
}
}
}
int main()
{
memset(h,-1,sizeof h);
memset(h1,-1,sizeof h1);
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i];
cin>>m;
while(m--){
int u,v,c;
cin>>u>>v>>c;
add(u,v,c);
add1(v,u,c);
}
dijkstra();
dijkstra1();
int min1=dist[1]+d[1]+p[1];
for(int i=2;i<=n;i++){
min1=min(min1,dist[i]+d[i]+p[i]);
}
cout<<min1<<endl;
return 0;
}