PAT
PAT (Advanced Level) Practice - I(1001-1050)
--------------------------------------------------------------------------------
1001-1167(已更新至最新!)
1001-1050
链接:https://pan.baidu.com/s/1Z4y8nR2VdgL9KWUQxwbKOA
提取码:9cv4
--------------------------------------------------------------------------------
更多详见>>
OJ题解系列 目录导航帖
--------------------------------------------------------------------------------
题目传送门
PAT (Advanced Level) Practice
--------------------------------------------------------------------------------
序
这里是PAT (Advanced Level) Practice - I(1001-1050)
这是一个全新的起点,我们完成了乙级考试的小目标,向着甲级考试的大目标前进,你将会看到一片新的世界,在数据结构和算法的大海里遨游
首先,我们讲讲两种考试的区别:
1.题面描述不同,乙级考试采用中文描述,甲级考试采用英文描述
2.题目数量不同,乙级考试是5道题,甲级考试是4道题
3.题目的分值不同,乙级考试的分值分布为15/20/20/20/25,甲级考试的分值分布为20/25/25/30
4.难度不同,甲级考试相对乙级考试来说会增加一个难度级别,主要体现在对数据结构的掌握上,如树和图——主要有BST/BBST/CBT/Heap/DAG,算法方面在原有的难度基础之上加深一点(比方说大模拟),引入了一些简单DP
知己知彼方能百战不殆,我们了解基本的区别之后,大家也不用太担心考试的难度问题,毕竟数据规模n不像竞赛要求那么高,很多算法用最普通的枚举方法往往也能取得满分!
接下来就是题解部分了,每道算法题都标注有对应的算法标签,对于那些易错、较难或是测试点比较特殊的题目会着重标注,本章推荐的题目有:
1003 Emergency (25 分) | 图论 + Dijkstra |
---|---|
1018 Public Bike Management (30 分) 1030 Travel Plan (30 分) | 图论 + Dijkstra + DFS |
1010 Radix (25 分) | 数论 + 进制 + 二分 |
1049 Counting Ones (30 分) | 数论 |
1014 Waiting in Line (30 分) 1017 Queueing at Bank (25 分) 1026 Table Tennis (30 分) | 大模拟 |
1021 Deepest Root (25 分) | 树,二叉树 |
1033 To Fill or Not to Fill (25 分) 1034 Head of a Gang (30 分) | 贪心 |
--------------------------------------------------------------------------------
1001 A+B Format (20 分)
算法标签: 模拟
注意点: 以3位为一个单位对数字进行划分,输出时要输出%03d
#include<bits/stdc++.h>
using namespace std;
int main(){
int a,b;
scanf("%d%d",&a,&b);
int c = a+b;
if(c<0){
cout << "-";
}
c = abs(c);
if(c < 1000){
cout << c % 1000 << endl;
}else if(c<1000000){
cout << c/1000 << ",";
printf("%03d\n",c%1000);
}else{
cout << c/1000000 << ",";
printf("%03d,%03d\n",c/1000%1000,c%1000);
}
return 0;
}
1002 A+B for Polynomials (25 分)
算法标签: 模拟 + 高精
注意点: 多项式加法,本质上和高精度加法一样,都是开一个比较大的数组,然后从尾到头依次累加,注意多项式加法不需要处理进位的问题
#include<bits/stdc++.h>
using namespace std;
double a[1005];
double b[1005];
double c[1005];
int main(){
int K;
int emax = -1;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
scanf("%d",&K);
for(int i=1;i<=K;i++){
int e;
double coeff;
scanf("%d%lf",&e,&coeff);
emax = max(emax,e);
a[e] = coeff;
}
scanf("%d",&K);
for(int i=1;i<=K;i++){
int e;
double coeff;
scanf("%d%lf",&e,&coeff);
emax = max(emax,e);
b[e] = coeff;
}
for(int i=emax;i>=0;i--){
c[i] = b[i] + a[i];
}
int cnt = 0;
for(int i=emax;i>=0;i--){
if(c[i]!=0){
cnt++;
}
}
cout << cnt;
for(int i=emax;i>=0;i--){
if(c[i]!=0){
printf(" ");
printf("%d %.1lf",i,c[i]);
}
}
return 0;
}
1003 Emergency (25 分)
算法标签: 图论 + Dijkstra
注意点: Dijkstra算法经典题,本题不用堆优化,
O
(
n
2
)
O(n^2)
O(n2)复杂度也能满分
本题考察的重点是最短路的松弛过程中,可直接更新最短路的数量,因为更新距离的过程就是更新数量的过程,两者算法在本质上是一样的(此处重点理解)
#include<bits/stdc++.h>
using namespace std;
int N,M,C1,C2;
int a[505];
int w[505];
int dp[505];
bool vis[505];
int num[505];
struct node{
int to;
int dis;
};
vector<node> G[505];
int maxdis = -1;
void Dijstra(int s){
memset(dp,0x3f,sizeof(dp));
dp[s] = 0;
w[s] = a[s];
num[s] = 1;
for(int i=0;i<N;i++){
int u = -1;
int minnum = INT_MAX;
for(int j=0;j<N;j++){
if(!vis[j] && dp[j]<minnum){
minnum = dp[j];
u = j;
}
}
if(u==-1){
return;
}
vis[u] = true;
for(int j=0;j<G[u].size();j++){
int v = G[u][j].to;
int dis = G[u][j].dis;
if(!vis[v]){
if(dp[u]+dis<dp[v]){
dp[v] = dp[u] + dis;
w[v] = w[u] + a[v];
num[v] = num[u];
}else if(dp[u]+dis==dp[v]){
if(w[v]<w[u]+a[v]){
w[v] = w[u] + a[v];
}
num[v] += num[u];
}
}
}
}
}
int main(){
cin >> N >> M >> C1 >> C2;
for(int i=0;i<N;i++){
cin >> a[i];
}
for(int i=0;i<M;i++){
int c1,c2,L;
cin >> c1 >> c2 >> L;
node temp;
temp.dis = L;
temp.to = c2;
G[c1].push_back(temp);
temp.to = c1;
G[c2].push_back(temp);
}
Dijstra(C1);
printf("%d %d\n",num[C2],w[C2]);
return 0;
}
1004 Counting Leaves (30 分)
算法标签: 树,二叉树 + DFS
注意点: DFS遍历整棵树,DFS的深度depth就是树的层次,统计每个层次的叶结点数量,最后输出结果
#include<bits/stdc++.h>
using namespace std;
int N,M;
int a[105];
vector<int> child[105];
int maxdepth = -1;
void dfs(int depth,int root){
if(child[root].size()==0){
a[depth]++;
}
if(depth>maxdepth){
maxdepth = depth;
}
for(int i=0;i<child[root].size();i++){
dfs(depth+1,child[root][i]);
}
}
int main(){
memset(a,0,sizeof(a));
cin >> N >> M;
for(int i=0;i<M;i++){
int id;
cin >> id;
int k;
cin >> k;
for(int j=0;j<k;j++){
int t;
cin >> t;
child[id].push_back(t);
}
}
dfs(1,1);
for(int i=1;i<=maxdepth;i++){
if(i!=1){
printf(" %d",a[i]);
}else{
printf("%d",a[i]);
}
}
return 0;
}
1005 Spell It Right (20 分)
算法标签: 模拟 + 字符串
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin >> s;
int total = 0;
for(int i=0;i<s.size();i++){
total += s[i] - '0';
}
int a[3];
bool flag = false;
a[0] = total / 100;
a[1] = total / 10 % 10;
a[2] = total % 10;
if(a[0]==0 && a[1]!=0){
a[0] = -1;
}else if(a[0]==0 && a[1]==0){
a[0] = -1;
a[1] = -1;
}
for(int i=0;i<3;i++){
switch(a[i]){
case 0:cout << "zero";break;
case 1:cout << "one";break;
case 2:cout << "two";break;
case 3:cout <<"three";break;
case 4:cout <<"four";break;
case 5:cout <<"five";break;
case 6:cout <<"six";break;
case 7:cout <<"seven";break;
case 8:cout <<"eight";break;
case 9:cout <<"nine";break;
default:break;
}
if(i==2){
}else{
if(a[i]==-1){
}else{
cout <<" ";
}
}
}
return 0;
}
1006 Sign In and Sign Out (25 分)
算法标签: 模拟 + 排序
注意点: 根据时间的变化情况确定是入库还是出库操作,注意满足题意的要求必须是当天进出各一次才算,单入库或者单出库都不在统计的范围内
#include<bits/stdc++.h>
using namespace std;
int Great(int h1,int m1,int s1,int h2,int m2,int s2){
if(h1!=h2){
return h1>h2;
}else if(m1!=m2){
return m1>m2;
}else if(s1!=s2){
return s1>s2;
}
}
int main(){
int M;
cin >> M;
int ans_h = 24, ans_m = 0, ans_s = 0;
int end_h = 0, end_m = 0, end_s = 0;
string s1,s2;
for(int i=0;i<M;i++){
string s;
cin >> s;
int s_h,s_m,s_s;
int e_h,e_m,e_s;
scanf("%d:%d:%d",&s_h,&s_m,&s_s);
scanf("%d:%d:%d",&e_h,&e_m,&e_s);
if(Great(ans_h,ans_m,ans_s,s_h,s_m,s_s)){
ans_h = s_h;
ans_m = s_m;
ans_s = s_s;
s1 = s;
}
if(Great(e_h,e_m,e_s,end_h,end_m,end_s)){
end_h = e_h;
end_m = e_m;
end_s = e_s;
s2 = s;
}
}
cout << s1 << " " << s2 << endl;
return 0;
}
1007 Maximum Subsequence Sum (25 分)
算法标签: 动态规划
注意点: DP状态转移方程为:
d
p
[
i
]
=
m
a
x
(
d
p
[
i
−
1
]
+
a
[
i
]
,
a
[
i
]
)
dp[i]=max(dp[i-1]+a[i],a[i])
dp[i]=max(dp[i−1]+a[i],a[i])
#include<bits/stdc++.h>
using namespace std;
int a[10005];
int dp[10005];
int site[10005];
int main(){
int K;
scanf("%d",&K);
bool f = false;
for(int i=0;i<K;i++){
scanf("%d",&a[i]);
if(a[i]>=0){
f = true;
}
}
dp[0] = a[0];
if(!f){
printf("0 %d %d\n",a[0],a[K-1]);
return 0;
}
for(int i=1;i<K;i++){
if(a[i]<dp[i-1]+a[i]){
dp[i] = dp[i-1]+a[i];
site[i] = site[i-1];
}else{
site[i] = i;
dp[i] = a[i];
}
}
int t;
int maxnum = -0x7f7f7f7f;
for(int i=0;i<K;i++){
if(dp[i]>maxnum){
maxnum = dp[i];
t = i;
}
}
printf("%d %d %d\n",dp[t],a[site[t]],a[t]);
return 0;
}
1008 Elevator (20 分)
算法标签: 模拟
注意点: 按时间T模拟电梯升降即可
#include<bits/stdc++.h>
using namespace std;
int main(){
int now = 0;
int N;
scanf("%d",&N);
long long cost = 0;
for(int i=0;i<N;i++){
int t;
scanf("%d",&t);
if(t>now){
cost += (t-now)*6;
cost += 5;
}else if(now==t){
cost += 5;
}else{
cost += (now-t)*4;
cost += 5;
}
now = t;
}
printf("%lld\n",cost);
return 0;
}
1009 Product of Polynomials (25 分)
算法标签: 模拟 + 高精
注意点: 多项式乘法,本质上和高精度乘法一样,都是开一个比较大的数组,然后从尾到头依次相乘,公式为
C
[
k
]
=
a
[
i
]
∗
b
[
j
]
,
i
+
j
=
k
C[k]=a[i]*b[j],i+j=k
C[k]=a[i]∗b[j],i+j=k,注意多项式乘法需要处理进位的问题,进位可能有多位
注:P1002/P1009可一起做,方法类似
#include<bits/stdc++.h>
using namespace std;
double a[2005];
double b[2005];
double c[2005];
int main(){
int K;
int emax = -1;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
scanf("%d",&K);
for(int i=1;i<=K;i++){
int e;
double coeff;
scanf("%d%lf",&e,&coeff);
emax = max(emax,e);
a[e] = coeff;
}
scanf("%d",&K);
for(int i=1;i<=K;i++){
int e;
double coeff;
scanf("%d%lf",&e,&coeff);
emax = max(emax,e);
b[e] = coeff;
}
for(int i=emax;i>=0;i--){
for(int j=emax;j>=0;j--){
if(a[i]!=0.0 && b[j]!=0.0){
c[i+j] += a[i] * b[j];
}
}
}
int cnt = 0;
for(int i=2*emax;i>=0;i--){
if(c[i]!=0.0){
cnt++;
}
}
cout << cnt;
for(int i=2*emax;i>=0;i--){
if(c[i]!=0.0){
printf(" ");
printf("%d %.1lf",i,c[i]);
}
}
return 0;
}
1010 Radix (25 分)
算法标签: 数论 + 进制 + 二分
注意点: 一道好题!这道题目把进制扩展到无限大的情况,比如1001进制下的10
(
1
0
1001
)
(10_{1001})
(101001)就是十进制下的1001
(
100
1
10
)
(1001_{10})
(100110),这个时候,若采用枚举进制的方法显然会TLE,因此,只能采用二分的方法,枚举进制,若在该进制下的数比预期大,那就缩小进制,否则就扩大,直到缩小的范围为一个数为止,此数即为答案
#include<bits/stdc++.h>
using namespace std;
long long tag,radix;
char N1[15],N2[15];
char temp[15];
int len1,len2;
void convert_N1(long long &num1,long long radix){
for(int i=0;i<len1;i++){
if(N1[i]>='a' && N1[i]<='z'){
num1 = num1*radix + N1[i] - 'a' + 10;
}else{
num1 = num1*radix + N1[i] - '0';
}
if(num1<0){
num1 = -1;
break;
}
}
}
void find_N2_max(long long &minn){
char max_c=0;
for(int i=0;i<len2;i++){
max_c = max(max_c,N2[i]);
}
if(max_c>='a' && max_c<='z'){
minn = max_c -'a' + 11;
}else{
minn = max_c -'0' +1;
}
}
int cmp(char N2[],long long mid,long long L){
long long num2 = 0;
for(int i=0;i<len2;i++){
if(N2[i]>='a' && N2[i]<='z'){
num2 = num2*mid + N2[i]-'a'+10;
}else{
num2 = num2*mid + N2[i]-'0';
}
if(num2<0){
return 1;
}
}
if(num2==L){
return 0;
}else if(num2>L){
return 1;
}else{
return -1;
}
}
long long binary_search(long long left,long long right,long long L){
while(left<=right){
long long mid = (left+right)/2;
int f = cmp(N2,mid,L);
if(f==0){
return mid;
}else if(f<0){
left = mid+1;
}else{
right = mid-1;
}
}
return -1;
}
int main(){
scanf("%s%s%lld%lld",N1,N2,&tag,&radix);
if(tag == 2){
swap(N1,N2);
}
len1 = strlen(N1);
len2 = strlen(N2);
long long num = 0;
long long left_N,right_N;
convert_N1(num,radix);
find_N2_max(left_N);
right_N = max(left_N,num+1);
long long ans = binary_search(left_N,right_N,num);
if(ans == -1){
printf("Impossible\n");
}else{
printf("%lld\n",ans);
}
return 0;
}
1011 World Cup Betting (20 分)
算法标签: 模拟 + 字符串
#include<bits/stdc++.h>
using namespace std;
double a[5][5];
string s = " WTL";
int b[5];
int main(){
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
scanf("%lf",&a[i][j]);
}
}
double res = 1.0;
for(int i=1;i<=3;i++){
double minn = -1.0;
int site;
for(int j=1;j<=3;j++){
if(a[i][j]>minn){
minn = a[i][j];
site = j;
}
}
b[i] = site;
res *= minn;
}
res = (res*0.65-1)*2;
for(int i=1;i<=3;i++){
printf("%c ",s[b[i]]);
}
printf("%.2lf\n",res);
return 0;
}
1012 The Best Rank (25 分)
算法标签: 模拟 + 排序
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
struct Student{
int id;
int grade[4];
}stu[2010];
char course[10] = {'A','C','M','E'};
int Rank[maxn][5] = {0};
int now;
bool cmp(Student a,Student b){
return a.grade[now] > b.grade[now];
}
int main(){
int n,m;
cin >> n >> m;
for(int i=0;i<n;i++){
scanf("%d%d%d%d",&stu[i].id,&stu[i].grade[1],
&stu[i].grade[2],&stu[i].grade[3]);
stu[i].grade[0] = (stu[i].grade[1] + stu[i].grade[2] + stu[i].grade[3])/3;
}
for(now = 0; now <= 3;now++){
sort(stu,stu+n,cmp);
Rank[stu[0].id][now] = 1;
for(int i=1;i<n;i++){
if(stu[i].grade[now] == stu[i-1].grade[now]){
Rank[stu[i].id][now] = Rank[stu[i-1].id][now];
}else{
Rank[stu[i].id][now] = i+1;
}
}
}
int q;
for(int i=0;i<m;i++){
scanf("%d",&q);
if(Rank[q][0] == 0){
cout << "N/A" << endl;
}else{
int t = INT_MAX;
int site = 0;
for(int j=0;j<=3;j++){
if(Rank[q][j]<t){
t = Rank[q][j];
site = j;
}
}
printf("%d %c\n",t,course[site]);
}
}
return 0;
}
1013 Battle Over Cities (25 分)
算法标签: 图论 + 连通块
注意点: 这道题本质上是求连通块的数量,可采用DFS/BFS的方法进行搜索连通分量,最后所需修建的道路数量即为连通块-1
#include<bits/stdc++.h>
using namespace std;
int N,M,K;
vector<int> G[1005];
bool vis[1005];
void DFS(int u){
vis[u] = true;
for(int i=0;i<G[u].size();i++){
if(!vis[G[u][i]]){
DFS(G[u][i]);
}
}
}
int main(){
scanf("%d%d%d",&N,&M,&K);
for(int i=0;i<M;i++){
int a,b;
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
for(int i=1;i<=K;i++){
int t;
scanf("%d",&t);
memset(vis,0,sizeof(vis));
vis[t] = true;
int cnt = 0;
for(int j=1;j<=N;j++){
if(!vis[j]){
DFS(j);
cnt++;
}
}
printf("%d\n",cnt-1);
}
return 0;
}
1014 Waiting in Line (30 分)
算法标签: 大模拟
注意点: 一道好题!
\quad\quad
这是一道大模拟的优质题目,模拟了窗口的排队过程,我们需要根据题意明白整个工作流程,根据当前时间(nowtime),服务结束时间(endtime),以及每个窗口的队伍数量封装成一个窗口结构体,依照输入数据的队列,反复取出等待队列的队头,进行服务,快进时间,再将等候区(waiting line)之后的队首取出,插入该窗口的末端
#include<bits/stdc++.h>
using namespace std;
int N,M,K,Q;
int c[1005];
int qtime[1005];
struct windows{
int nowtime;
int endtime;
queue<int> q;
};
windows w[25];
int time_min(int h,int m){
return h*60+m;
}
void min_time(int t){
printf("%02d:%02d\n",t/60,t%60);
}
int main(){
scanf("%d%d%d%d",&N,&M,&K,&Q);
for(int i=1;i<=K;i++){
scanf("%d",&c[i]);
}
int start = time_min(8,0);
int end = time_min(17,0);
for(int i=1;i<=N;i++){
w[i].nowtime = time_min(8,0);
w[i].endtime = time_min(8,0);
}
int now = 1;
int maxnum = N*M;
for(now = 1;now<=K && now<=maxnum;){
for(int j=1;j<=N;j++){
if(w[j].q.size()<M){
if(w[j].endtime >= end){
w[j].q.push(c[now]);
now++;
}else{
w[j].endtime += c[now];
qtime[now] = w[j].endtime;
w[j].q.push(c[now]);
now++;
}
}
if(now>K || now>maxnum){
break;
}
}
}
for(now;now<=K;now++){
int u = -1;
int mintime = INT_MAX;
for(int j=1;j<=N;j++){
int t = w[j].q.front();
if(t+w[j].nowtime < mintime){
mintime = t + w[j].nowtime;
u = j;
}
}
if(w[u].endtime>=end){
break;
}
int f = w[u].q.front();
w[u].nowtime += f;
w[u].q.pop();
w[u].endtime += c[now];
w[u].q.push(c[now]);
qtime[now] = w[u].endtime;
}
for(int i=1;i<=Q;i++){
int t;
scanf("%d",&t);
if(qtime[t]==0){
printf("Sorry\n");
}else{
min_time(qtime[t]);
}
}
return 0;
}
1015 Reversible Primes (20 分)
算法标签: 数论 + 素数
注意点: 可用素数筛预处理素数集合,加快程序处理速度
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
bool p[maxn] = {1,1,0};
void init(){
for(int i=2;i<maxn;i++){
if(!p[i]){
for(int j=2*i;j<maxn;j+=i){
p[j] = 1;
}
}
}
}
int main(){
init();
int n;
int D;
while(scanf("%d",&n)!=EOF){
if(n<0){
break;
}
scanf("%d",&D);
if(!p[n]){
int ans = 0;
while(n){
ans = ans*D + (n%D);
n/=D;
}
if(!p[ans]){
printf("Yes\n");
}else{
printf("No\n");
}
}else{
printf("No\n");
}
}
return 0;
}
1016 Phone Bills (25 分)
算法标签: 模拟 + 排序
#include<bits/stdc++.h>
using namespace std;
int a[30];
struct info{
string name;
int month;
int day;
int hour;
int min;
int status;
};
info in[1005];
bool cmp(info i1,info i2){
if(i1.name!=i2.name){
return i1.name < i2.name;
}else if(i1.month!=i2.month){
return i1.month < i2.month;
}else if(i1.day!=i2.day){
return i1.day < i2.day;
}else if(i1.hour!=i2.hour){
return i1.hour < i2.hour;
}else{
return i1.min < i2.min;
}
}
int main(){
for(int i=0;i<24;i++){
cin >> a[i];
}
int N;
cin >> N;
for(int i=0;i<N;i++){
cin >> in[i].name;
scanf("%d:%d:%d:%d",&in[i].month,&in[i].day,&in[i].hour,&in[i].min);
string t;
cin >> t;
if(t == "on-line"){
in[i].status = 0;
}else{
in[i].status = 1;
}
}
sort(in,in+N,cmp);
int cnt = 0;
double total = 0;
for(int i=1;i<=N;i++){
if(in[i-1].name == in[i].name){
if(in[i-1].status == 0 && in[i].status == 1){
if(cnt == 0){
cout << in[i].name << " ";
printf("%02d\n",in[i].month);
}
printf("%02d:%02d:%02d %02d:%02d:%02d",in[i-1].day,in[i-1].hour,in[i-1].min,
in[i].day,in[i].hour,in[i].min);
int d1 = in[i-1].day;
int h1 = in[i-1].hour;
int m1 = in[i-1].min;
int d2 = in[i].day;
int h2 = in[i].hour;
int m2 = in[i].min;
int fee = 0;
int count = 0;
while(d1<d2 || h1<h2 || m1<m2){
count++;
m1++;
fee += a[h1];
if(m1==60){
m1 = 0;
h1 ++;
}
if(h1==24){
h1 = 0;
d1 ++;
}
}
cnt++;
double res = 1.0*fee/100.0;
total += res;
printf(" %d $%.2lf\n",count,res);
}
}else{
if(cnt){
printf("Total amount: $%.2lf\n",total);
}
total = 0.0;
cnt = 0;
}
}
return 0;
}
1017 Queueing at Bank (25 分)
算法标签: 大模拟
注意点: 一道好题!建议与P1014进行对比
这道题本质上是大模拟,需要对整个模拟的流程模块化处理,这里需要注意到达时间、开始服务时间、结束时间是3个不同的概念!
#include<bits/stdc++.h>
using namespace std;
int N,K;
struct custom{
int arrival;
int last;
};
custom c;
int converttime(int h,int m,int s){
return h*3600 + m*60 + s;
}
vector<custom> v;
bool cmp(custom c1,custom c2){
return c1.arrival < c2.arrival;
}
int w[105];
int main(){
scanf("%d%d",&N,&K);
int start = converttime(8,0,0);
int end = converttime(17,0,0);
for(int i=0;i<N;i++){
char time[105];
int servertime;
scanf("%s%d",time,&servertime);
int h,m,d;
h = 10*(time[0]-'0') + (time[1]-'0');
m = 10*(time[3]-'0') + (time[4]-'0');
d = 10*(time[6]-'0') + (time[7]-'0');
int t = converttime(h,m,d);
if(t>end){
continue;
}else{
c.arrival = t;
c.last = servertime;
v.push_back(c);
}
}
sort(v.begin(),v.end(),cmp);
for(int i=1;i<=K;i++){
w[i] = start;
}
int total = 0;
double ave = 0.0;
for(int i=0;i<v.size();i++){
int u = -1;
int mintime = INT_MAX;
for(int j=1;j<=K;j++){
if(w[j]<mintime){
mintime = w[j];
u = j;
}
}
if(w[u]<=v[i].arrival){
w[u] = v[i].arrival + v[i].last*60;
}else{
total += (w[u]-v[i].arrival);
w[u] += v[i].last*60;
}
}
ave = total/60.0/(v.size()*1.0);
printf("%.1lf\n",ave);
return 0;
}
1018 Public Bike Management (30 分)
算法标签: 图论 + Dijkstra + DFS
注意点: 本题是Dijkstra的进化版本,即带DFS的Dijkstra,DFS的目的是提前存储可能的路径顶点(dijkstra算法中保存),完成最短路算法之后,我们再对保存的路径进行搜索,取出满足题意最大的结果,输出。
注意此题与P1003的对比!
#include<bits/stdc++.h>
using namespace std;
int Cmax,N,SP,M;
struct node{
int v;
int dis;
};
bool vis[505];
int dp[505];
int weight[505];
vector<node> G[505];
vector<int> pre[505];
vector<int> ans;
vector<int> tempans;
int sendmax = INT_MAX;
int take;
void dijstra(int s){
fill(dp,dp+N+1,INT_MAX);
dp[s] = 0;
memset(vis,0,sizeof(vis));
for(int i=0;i<N+1;i++){
int u = -1;
int minnum = INT_MAX;
for(int j=0;j<=N;j++){
if(!vis[j] && dp[j]<minnum){
minnum = dp[j];
u = j;
}
}
if(u==-1){
return;
}
vis[u] = true;
for(int j=0;j<G[u].size();j++){
int v = G[u][j].v;
int dis = G[u][j].dis;
if(!vis[v]){
if(dp[u]+dis<dp[v]){
dp[v] = dp[u] + dis;
pre[v].clear();
pre[v].push_back(u);
}else if(dp[u]+dis==dp[v]){
pre[v].push_back(u);
}
}
}
}
}
void dfs(int v){
if(v == 0){
int Need = 0;
int Remain = 0;
tempans.push_back(v);
for(int i=tempans.size()-2;i>=0;i--){
if(weight[tempans[i]]>0){
Remain += weight[tempans[i]];
}else{
if(Remain>=abs(weight[tempans[i]])){
Remain -= abs(weight[tempans[i]]);
}else{
Need += (abs(weight[tempans[i]])-Remain);
Remain = 0;
}
}
}
if(Need<sendmax){
sendmax = Need;
ans = tempans;
take = Remain;
}else if(Need == sendmax){
if(Remain<take){
take = Remain;
ans = tempans;
}
}
tempans.pop_back();
return;
}
tempans.push_back(v);
for(int i=0;i<pre[v].size();i++){
dfs(pre[v][i]);
}
tempans.pop_back();
}
int main(){
cin >> Cmax >> N >> SP >> M;
for(int i=1;i<=N;i++){
cin >> weight[i];
}
for(int i=0;i<M;i++){
int c1,c2,l;
cin >> c1 >> c2 >> l;
node temp;
temp.v = c2;
temp.dis = l;
G[c1].push_back(temp);
temp.v = c1;
G[c2].push_back(temp);
}
for(int i=1;i<=N;i++){
weight[i] -= Cmax/2;
}
dijstra(0);
dfs(SP);
printf("%d ",sendmax);
for(int i=ans.size()-1;i>=0;i--){
if(i==ans.size()-1){
printf("%d",ans[i]);
}else{
printf("->%d",ans[i]);
}
}
printf(" %d\n",take);
return 0;
}
1019 General Palindromic Number (20 分)
算法标签: 数论 + 模拟
注意点: 回文数的判断,最基本的算法是遍历前半段
O
(
n
2
)
O(\frac{n}{2})
O(2n)个下标,观察其与后半段是否相等,相等即是回文数
#include<bits/stdc++.h>
using namespace std;
int a[105];
int main(){
int n,b;
cin >> n >> b;
int cnt = 0;
while(n){
a[cnt++] = n%b;
n/=b;
}
bool flag = true;
for(int i=0;i<cnt/2;i++){
if(a[i] == a[cnt-i-1]){
continue;
}else{
flag = false;
}
}
if(flag){
cout << "Yes" << endl;
}else{
cout << "No" << endl;
}
for(int i=cnt-1;i>=0;i--){
if(i!=0){
cout << a[i] << " ";
}else{
cout << a[i] << endl;
}
}
return 0;
}
1020 Tree Traversals (25 分)
算法标签: 树,二叉树 + 遍历
注意点: 首先输入中序遍历和后序遍历,建立一棵树,然后从根结点出发,进行层次遍历
#include<bits/stdc++.h>
using namespace std;
int post[35];
int in[35];
struct node{
int data;
node* lchild;
node* rchild;
};
node* root = NULL;
node* newnode(int v){
node* Node = new node;
Node->data = v;
Node->lchild = NULL;
Node->rchild = NULL;
return Node;
}
node* Create(int inL,int inR,int postL,int postR){
if(postL>postR){
return NULL;
}
int d = post[postR];
int k;
for(int i=inL;i<=inR;i++){
if(in[i]==d){
k = i;
break;
}
}
int numleft = k-inL;
node* Node = new node;
Node->data = d;
Node->lchild = Create(inL,k-1,postL,postL+numleft-1);
Node->rchild = Create(k+1,inR,postL+numleft,postR-1);
return Node;
}
queue<node*> q;
int n;
void Level(node* root){
int T = n;
q.push(root);
while(!q.empty()){
node* f = q.front();
q.pop();
if(T==1){
printf("%d\n",f->data);
}else{
printf("%d ",f->data);
}
T--;
if(f->lchild){
q.push(f->lchild);
}
if(f->rchild){
q.push(f->rchild);
}
}
}
int main(){
cin >> n;
for(int i=0;i<n;i++){
cin >> post[i];
}
for(int i=0;i<n;i++){
cin >> in[i];
}
root = Create(0,n-1,0,n-1);
Level(root);
return 0;
}
1021 Deepest Root (25 分)
算法标签: 树,二叉树
注意点: 一道好题!这道题目需要求出一棵树上最远的点集,也就是说,假设有一个点集A,另一个点集B,A中任意一点到B中任意一点的距离与树中最远两个顶点的距离相同,那么这就是Deepest Root!
以下我们不加证明的给出这道题的解法(详细解法可参考相应的数学证明):
1.首先从任意一点出发,遍历到最深的点,依次记录,这些点就是点集A
2.从点集A的任意一点出发,遍历最深的点,依次记录,得到点集B
3.A+B即为题目所求
#include<bits/stdc++.h>
using namespace std;
vector<int> G[10005];
bool vis[10005];
set<int> ans1;
set<int> ans2;
set<int> ans;
void dfs(int u){
vis[u] = true;
for(int i=0;i<G[u].size();i++){
if(!vis[G[u][i]]){
dfs(G[u][i]);
}
}
}
void dfs1(int u,int depth,int &maxdepth){
vis[u] = true;
if(depth>maxdepth){
ans1.clear();
maxdepth = depth;
ans1.insert(u);
}else if(depth==maxdepth){
ans1.insert(u);
}
for(int i=0;i<G[u].size();i++){
if(!vis[G[u][i]]){
dfs1(G[u][i],depth+1,maxdepth);
}
}
}
void dfs2(int u,int depth,int &maxdepth){
vis[u] = true;
if(depth>maxdepth){
ans2.clear();
maxdepth = depth;
ans2.insert(u);
}else if(depth==maxdepth){
ans2.insert(u);
}
for(int i=0;i<G[u].size();i++){
if(!vis[G[u][i]]){
dfs2(G[u][i],depth+1,maxdepth);
}
}
}
int main(){
int N;
scanf("%d",&N);
for(int i=1;i<N;i++){
int a,b;
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
int cnt = 0;
for(int i=1;i<=N;i++){
if(!vis[i]){
dfs(i);
cnt++;
}
}
if(cnt>1){
printf("Error: %d components\n",cnt);
}else{
memset(vis,0,sizeof(vis));
int maxdepth = -1;
dfs1(1,0,maxdepth);
memset(vis,0,sizeof(vis));
maxdepth = -1;
dfs2(*ans1.begin(),0,maxdepth);
for(auto it=ans1.begin();it!=ans1.end();it++){
ans.insert(*it);
}
for(auto it=ans2.begin();it!=ans2.end();it++){
ans.insert(*it);
}
for(auto it=ans.begin();it!=ans.end();it++){
printf("%d\n",*it);
}
}
return 0;
}
1022 Digital Library (30 分)
算法标签: 排序,哈希
#include<bits/stdc++.h>
using namespace std;
int N;
map<string,set<int> > mptitle,mpname,mpword,mppublisher,mpyear;
void input(){
cin >> N;
string title,name,word,publisher,year;
for(int i=0;i<N;i++){
int ID;
cin >> ID;
getchar();
getline(cin,title);
mptitle[title].insert(ID);
getline(cin,name);
mpname[name].insert(ID);
while(1){
cin >> word;
mpword[word].insert(ID);
char c = getchar();
if(c=='\n'){
break;
}
}
getline(cin,publisher);
mppublisher[publisher].insert(ID);
getline(cin,year);
mpyear[year].insert(ID);
}
}
void print(map<string,set<int> > &mp,string s){
if(mp.find(s)!=mp.end()){
for(auto it = mp[s].begin();it!=mp[s].end();it++){
printf("%07d\n",*it);
}
}else{
cout << "Not Found" << endl;
}
}
void query(){
int M;
cin >> M;
for(int i=0;i<M;i++){
int type;
scanf("%d: ",&type);
printf("%d: ",type);
string q;
getline(cin,q);
cout << q << endl;
if(type == 1){
print(mptitle,q);
}else if(type == 2){
print(mpname,q);
}else if(type == 3){
print(mpword,q);
}else if(type == 4){
print(mppublisher,q);
}else{
print(mpyear,q);
}
}
}
int main(){
input();
query();
return 0;
}
1023 Have Fun with Numbers (20 分)
算法标签: 数论 + 高精
#include<bits/stdc++.h>
using namespace std;
struct bign{
int len;
int a[1005];
bign(){
memset(a,0,sizeof(a));
len = 0;
}
};
bign b1;
bign b2;
int n1[15];
int n2[15];
int main(){
string s;
cin >> s;
int len = s.size();
b1.len = len;
for(int i=len-1;i>=0;i--){
b1.a[len-i-1] = s[i]-'0';
}
int jw = 0;
for(int i=0;i<len;i++){
b2.a[i] = b1.a[i]*2 + jw;
jw = b2.a[i]/10;
b2.a[i] %= 10;
}
if(jw){
b2.a[len] = jw;
b2.len = b1.len+1;
}else{
b2.len = b1.len;
}
for(int i=0;i<b1.len;i++){
n1[b1.a[i]%10]++;
}
for(int i=0;i<b2.len;i++){
n2[b2.a[i]%10]++;
}
bool f = true;
for(int i=0;i<=9;i++){
if(n1[i] == n2[i]){
continue;
}else{
f = false;
break;
}
}
if(f){
printf("Yes\n");
}else{
printf("No\n");
}
for(int i=b2.len-1;i>=0;i--){
printf("%d",b2.a[i]);
}
printf("\n");
return 0;
}
1024 Palindromic Number (25 分)
算法标签: 数论 + 高精 + 字符串
#include<bits/stdc++.h>
using namespace std;
struct bign{
int len;
int a[1005];
bign(){
memset(a,0,sizeof(a));
len = 0;
}
};
bign x1;
bign x2;
bign x3;
bool isPalin(bign x){
bool f = true;
for(int i=0;i<x.len/2;i++){
if(x.a[i] == x.a[x.len-1-i]){
continue;
}else{
f = false;
break;
}
}
return f;
}
int main(){
string N;
int K;
cin >> N;
cin >> K;
int l = N.size();
for(int i=0;i<l;i++){
x1.a[i] = N[i]-'0';
}
for(int i=0;i<l;i++){
x2.a[l-i-1] = N[i] - '0';
}
x1.len = l;
x2.len = l;
int cnt = 0;
if(isPalin(x1)){
cout << N << endl;
printf("0\n");
return 0;
}
while(K--){
cnt++;
int jw = 0;
for(int i=0;i<x1.len;i++){
x3.a[i] = x1.a[i] + x2.a[i] + jw;
jw = x3.a[i] / 10;
x3.a[i] %= 10;
}
if(jw){
x3.a[x1.len] = jw;
x3.len = x1.len+1;
}else{
x3.len = x1.len;
}
if(isPalin(x3)){
break;
}
for(int i=0;i<x3.len;i++){
x1.a[i] = x3.a[i];
x2.a[x3.len-i-1] = x3.a[i];
}
x1.len = x3.len;
x2.len = x3.len;
}
for(int i=x3.len-1;i>=0;i--){
printf("%d",x3.a[i]);
}
printf("\n");
printf("%d\n",cnt);
return 0;
}
1025 PAT Ranking (25 分)
算法标签: 排序
#include<bits/stdc++.h>
using namespace std;
struct student{
long long id;
int score;
int final_rank;
int local_num;
int local_rank;
};
student s[30005];
bool cmp(student s1,student s2){
if(s1.score!=s2.score){
return s1.score > s2.score;
}else{
return s1.id < s2.id;
}
}
int main(){
int N;
cin >> N;
int cnt = 0;
int class_num = 1;
for(int i=0;i<N;i++){
int K;
cin >> K;
for(int j=0;j<K;j++){
scanf("%lld%d",&s[cnt].id,&s[cnt].score);
s[cnt++].local_num = class_num;
}
class_num++;
sort(s+cnt-K,s+cnt,cmp);
s[cnt-K].local_rank = 1;
for(int j=1;j<K;j++){
if(s[cnt-K+j].score == s[cnt-K+j-1].score){
s[cnt-K+j].local_rank = s[cnt-K+j-1].local_rank;
}else{
s[cnt-K+j].local_rank = j+1;
}
}
}
sort(s,s+cnt,cmp);
s[0].final_rank = 1;
for(int j=1;j<cnt;j++){
if(s[j].score == s[j-1].score){
s[j].final_rank = s[j-1].final_rank;
}else{
s[j].final_rank = j+1;
}
}
if(cnt){
cout << cnt << endl;
for(int i=0;i<cnt;i++){
printf("%013lld %d %d %d\n",s[i].id,s[i].final_rank,s[i].local_num,s[i].local_rank);
}
}
return 0;
}
1026 Table Tennis (30 分)
算法标签: 大模拟
注意点: 一道好题!这道大模拟是几百题之中最难的一道
首先我们需要明白题目的意思,题目是想让我们模拟球馆的场地分配,每组人来,就分配相应的场地。按照先到先得,VIP优先预置的策略,模拟一天的分配,根据这两个策略,可分成如下4类讨论:(变量有顾客(VIP)、球桌(VIP))
1.(当前来到的)是VIP顾客,(当前空闲的且编号最小)是VIP球桌,此时直接分配[当前顾客使用当前球桌]
2.是VIP顾客,不是VIP球桌,这时候,我们需要遍历所有的VIP球桌,如果球桌使用的结束时间(endtime)
<
=
<=
<=顾客的到达时间(arrivetime),那么就分配VIP编号中最小的(且满足条件),否则就分配普通球桌中编号最小的(且满足条件)
3.不是VIP顾客,是VIP球桌,此时需扫描VIP队列中的队首,若VIP顾客的到达时间(arrivetime)
>
=
>=
>=球桌使用的结束时间(endtime),那么这张桌子应该预留给VIP顾客,而不是普通顾客,若找不到满足上述条件的VIP顾客,我们才将该VIP桌子分配给普通顾客
4.不是VIP顾客,也不是VIP球桌,此时直接分配即可
#include<bits/stdc++.h>
using namespace std;
int N,K,M;
struct player{
int arrivetime;
int starttime;
int traintime;
bool isVIP;
};
player tempP;
struct table{
int endtime;
int num;
bool isVIP;
};
table t[105];
vector<player> v;
bool cmp1(player p1,player p2){
return p1.arrivetime < p2.arrivetime;
}
bool cmp2(player p1,player p2){
if(p1.starttime!=p2.starttime){
return p1.starttime < p2.starttime;
}else{
return p1.isVIP > p2.isVIP;
}
}
int nextVIP(int k){
k++;
while(k<v.size() && v[k].isVIP == 0){
k++;
}
return k;
}
int converttime(int h,int m,int s){
return h*3600 + m*60 +s;
}
void allocate(int pID,int tID){
if(v[pID].arrivetime<=t[tID].endtime){
v[pID].starttime = t[tID].endtime;
}else{
v[pID].starttime = v[pID].arrivetime;
}
t[tID].endtime = v[pID].starttime + v[pID].traintime;
t[tID].num++;
}
int main(){
scanf("%d",&N);
int start = converttime(8,0,0);
int end = converttime(21,0,0);
for(int i=0;i<N;i++){
int h,m,d;
int last;
int isVIP;
scanf("%d:%d:%d%d%d",&h,&m,&d,&last,&isVIP);
last = min(last,120);
tempP.arrivetime = converttime(h,m,d);
if(tempP.arrivetime>=end){
continue;
}else{
tempP.isVIP = isVIP;
tempP.starttime = end;
tempP.traintime = last*60;
v.push_back(tempP);
}
}
scanf("%d%d",&K,&M);
for(int i=1;i<=K;i++){
t[i].endtime = start;
t[i].num = 0;
t[i].isVIP = 0;
}
for(int i=0;i<M;i++){
int number;
scanf("%d",&number);
t[number].isVIP = 1;
}
sort(v.begin(),v.end(),cmp1);
int i = 0,VIPnow = -1;
VIPnow = nextVIP(VIPnow);
while(i<v.size()){
int u = -1;
int mintime = INT_MAX;
for(int j=1;j<=K;j++){
if(t[j].endtime < mintime){
mintime = t[j].endtime;
u = j;
if(t[j].endtime <= v[i].arrivetime){
break;
}
}
}
if(t[u].endtime>=end){
break;
}
if(v[i].isVIP == 1 && i<VIPnow){
i++;
continue;
}
if(t[u].isVIP == 1){
if(v[i].isVIP == 1){
allocate(i,u);
if(i == VIPnow){
VIPnow = nextVIP(VIPnow);
}
i++;
}else{
if(VIPnow<v.size() && v[VIPnow].arrivetime<=t[u].endtime){
allocate(VIPnow,u);
VIPnow = nextVIP(VIPnow);
}else{
allocate(i,u);
i++;
}
}
}else{
if(v[i].isVIP == 0){
allocate(i,u);
i++;
}else{
int uu=-1;
int mmintime = INT_MAX;
for(int j=1;j<=K;j++){
if(t[j].isVIP ==1 && t[j].endtime<mmintime){
mmintime = t[j].endtime;
uu=j;
}
}
if(uu!=-1 && (t[uu].endtime <= v[i].arrivetime)){
allocate(i,uu);
if(VIPnow == i){
VIPnow = nextVIP(VIPnow);
}
i++;
}else{
allocate(i,u);
if(VIPnow == i){
VIPnow = nextVIP(VIPnow);
}
i++;
}
}
}
}
sort(v.begin(),v.end(),cmp2);
for(int i=0;i<v.size() && v[i].starttime<end;i++){
int t1 = v[i].arrivetime;
int t2 = v[i].starttime;
printf("%02d:%02d:%02d ",t1/3600,t1/60%60,t1%60);
printf("%02d:%02d:%02d ",t2/3600,t2/60%60,t2%60);
printf("%.0lf\n",round((t2-t1)/60.0));
}
for(int j=1;j<=K;j++){
if(j==1){
printf("%d",t[j].num);
}else{
printf(" %d",t[j].num);
}
}
return 0;
}
1027 Colors in Mars (20 分)
算法标签: 模拟 + 字符串
#include<bits/stdc++.h>
using namespace std;
string s = "0123456789ABC";
int main(){
cout << "#";
for(int i=1;i<=3;i++){
int t;
cin >> t;
int a,b;
a = t/13;
b = t%13;
cout << s[a] << s[b];
}
return 0;
}
1028 List Sorting (25 分)
算法标签: 排序
#include<bits/stdc++.h>
using namespace std;
struct stu{
int id;
string name;
int grade;
};
stu s[100005];
bool cmp1(stu s1,stu s2){
return s1.id < s2.id;
}
bool cmp2(stu s1,stu s2){
if(s1.name!=s2.name){
return s1.name < s2.name;
}else{
return s1.id < s2.id;
}
}
bool cmp3(stu s1,stu s2){
if(s1.grade!=s2.grade){
return s1.grade < s2.grade;
}else{
return s1.id < s2.id;
}
}
int main(){
cin.tie(0);
cout.tie(0);
int N,C;
cin >> N >> C;
for(int i=0;i<N;i++){
scanf("%d",&s[i].id);
cin >> s[i].name;
scanf("%d",&s[i].grade);
}
if(C==1){
sort(s,s+N,cmp1);
}else if(C==2){
sort(s,s+N,cmp2);
}else{
sort(s,s+N,cmp3);
}
for(int i=0;i<N;i++){
printf("%06d ",s[i].id);
cout << s[i].name;
printf(" %d\n",s[i].grade);
}
return 0;
}
1029 Median (25 分)
算法标签: 数论 + 中位数
注意点: 中位数算法,由于题目中给出的数据范围很大,因此排序求中位数不是很好的选择,我们采用枚举的方法,不断从A序列和B序列中取出队首元素,进行比较,小的元素计入,这样通过
O
(
n
)
O(n)
O(n)的时间得到了中位数
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
int a[maxn];
int b[maxn];
int main(){
int p,q;
scanf("%d",&p);
for(int i=0;i<p;i++){
scanf("%d",&a[i]);
}
a[p] = INT_MAX;
scanf("%d",&q);
for(int i=0;i<q;i++){
scanf("%d",&b[i]);
}
b[q] = INT_MAX;
int i = 0;
int j = 0;
int median = (p+q-1)/2;
int cnt = 0;
while(cnt<median){
if(a[i]<b[j]){
i++;
}else{
j++;
}
cnt++;
}
if(a[i]<b[j]){
printf("%d\n",a[i]);
}else{
printf("%d\n",b[j]);
}
return 0;
}
1030 Travel Plan (30 分)
算法标签: 图论 + Dijkstra + DFS
注意点: 和之前几道图论的题目类似,可参考P1003/P1018的解法
#include<bits/stdc++.h>
using namespace std;
int N,M,S,D;
struct node{
int v;
int dis;
int c;
};
vector<node> G[505];
int dp[505];
int cost[505];
bool vis[505];
int pre[505];
void dijstra(int s){
fill(dp,dp+N,INT_MAX);
fill(cost,cost+N,INT_MAX);
dp[s] = 0;
cost[s] = 0;
for(int i=0;i<N;i++){
int u = -1;
int minnum = INT_MAX;
for(int j=0;j<N;j++){
if(!vis[j] && dp[j]<minnum){
minnum = dp[j];
u = j;
}
}
if(u==-1){
return;
}
vis[u] = true;
for(int j=0;j<G[u].size();j++){
int v = G[u][j].v;
int dis = G[u][j].dis;
int c = G[u][j].c;
if(!vis[v]){
if(dp[u]+dis<dp[v]){
dp[v] = dp[u] + dis;
cost[v] = cost[u] +c;
pre[v] = u;
}else if(dp[u]+dis==dp[v]){
if(cost[u]+c<cost[v]){
cost[v] = cost[u] + c;
pre[v] = u;
}
}
}
}
}
}
void printpath(int D){
if(D==S){
printf("%d ",S);
return;
}
printpath(pre[D]);
printf("%d ",D);
}
int main(){
scanf("%d%d%d%d",&N,&M,&S,&D);
for(int i=0;i<M;i++){
int c1,c2,l,c;
scanf("%d%d%d%d",&c1,&c2,&l,&c);
node temp;
temp.v = c2;
temp.dis = l;
temp.c = c;
G[c1].push_back(temp);
temp.v = c1;
G[c2].push_back(temp);
}
dijstra(S);
printpath(D);
printf("%d ",dp[D]);
printf("%d\n",cost[D]);
return 0;
}
1031 Hello World for U (20 分)
算法标签: 模拟 + 字符串
注意点: 这道题目需要求出打印的字符串横竖的长度,其中竖向高度为
n
1
=
n
3
=
N
+
2
3
n_1=n_3=\frac{N+2}{3}
n1=n3=3N+2,横向的长度为
n
2
=
(
N
+
2
)
−
n
1
−
n
3
n_2=(N+2)-n_1-n_3
n2=(N+2)−n1−n3,按照长度顺序依次输出即可
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin >> s;
int N = s.size();
int n1,n3;
n1 = n3 = (N+2)/3;
int n2 = N+2 - n1 - n3;
for(int i=0;i<n1-1;i++){
cout << s[i];
for(int j=1;j<n2-1;j++){
cout << " ";
}
cout << s[N-1-i];
cout << endl;
}
for(int j=0;j<n2;j++){
cout << s[n1-1+j];
}
return 0;
}
1032 Sharing (25 分)
算法标签: 字符串 + 链表
注意点: 求解两个链表的最大公共后缀长度,可以在每个结点增添flag标记,首先遍历链表1,把经过的结点flag标记为true,然后遍历链表2,第一次找到flag为true的标签,从此之后都为公共后缀,输出结点地址即可
#include<bits/stdc++.h>
using namespace std;
struct node{
char value;
int next;
bool flag = false;
};
const int maxn = 1e5+5;
node n[maxn];
int main(){
int start1,start2;
int N;
scanf("%d%d%d",&start1,&start2,&N);
for(int i=0;i<N;i++){
int t;
scanf("%d ",&t);
scanf("%c %d",&n[t].value,&n[t].next);
}
while(start1!=-1){
n[start1].flag = true;
start1 = n[start1].next;
}
while(start2!=-1){
if(n[start2].flag==true){
break;
}else{
start2 = n[start2].next;
}
}
if(start2==-1){
printf("-1\n");
}else{
printf("%05d\n",start2);
}
return 0;
}
1033 To Fill or Not to Fill (25 分)
算法标签: 贪心
注意点: 一道好题!这是一道贪心算法的经典题目,我们可以从起点出发,模拟整个路程中的贪心过程。
1.首先,从起点出发,计算满油能开的最远距离,然后在这个距离内,找到一个最便宜的加油站,计算到这个加油站所需加的最少油量,若找不到,则在起点加满油,开到最近的下一个加油站。
2.然后,在下一个加油站处,仍旧计算满油能开的最远距离,找到一个最便宜的加油站,计算到这个加油站所需加的最少油量,若找不到,则在该加油站处加满油,开到最近的下一个加油站
3.如此反复循环,直到终点或不可达
不可达输出不可达,可达则输出最小花费
#include<bits/stdc++.h>
using namespace std;
struct gas_station{
double price;
int distance;
};
gas_station g[1005];
bool cmp(gas_station g1,gas_station g2){
return g1.distance < g2.distance;
}
int main(){
int Cmax,D,per,n;
scanf("%d%d%d%d",&Cmax,&D,&per,&n);
for(int i=0;i<n;i++){
scanf("%lf%d",&g[i].price,&g[i].distance);
}
g[n].distance = D;
g[n].price = 0.0;
sort(g,g+n,cmp);
if(g[0].distance!=0){
printf("The maximum travel distance = 0.00\n");
return 0;
}
double far_dis = 1.0*Cmax*per;
int now = 0;
double Cur = 0.0;
double total = 0.0;
while(now<n){
int next = -1;
if(g[now+1].distance-g[now].distance>far_dis){
break;
}
for(int i=now+1;i<=n;i++){
if(far_dis+g[now].distance>=g[i].distance){
if(g[i].price<g[now].price){
next = i;
break;
}
}else{
break;
}
}
if(next == -1){
double gas_price = (Cmax - Cur)*g[now].price;
Cur = Cmax*1.0;
Cur = Cur - (g[now+1].distance-g[now].distance)*1.0/(per*1.0);
total += gas_price;
now++;
}else{
double gas_need = (g[next].distance-g[now].distance)*1.0/(per*1.0);
if(Cur>gas_need){
Cur -= gas_need;
}else{
double gas_price = (gas_need-Cur)*g[now].price;
total += gas_price;
Cur = 0.0;
}
now = next;
}
}
if(now == n){
printf("%.2lf\n",total);
}else{
printf("The maximum travel distance = %.2lf\n",g[now].distance+far_dis);
}
return 0;
}
1034 Head of a Gang (30 分)
算法标签: 贪心
注意点: 看似是一道并查集操作,实际上是图论的DFS搜索,统计一个连通块内顶点的数量难度相对不大,但是统计边权之和是本题的难度所在,如果一个连通块中,不存在环,边权直接相加即可,但是本题中可能出现环,此时要先加边权,加完边权置为0(防止重复累加边权),再访问下一个顶点,这样能够保证有边就加(不少加边权),如此才能统计出正确的结果,gang是指点权最大的点,每访问一个点,实时更新gang的归属即可。
#include<bits/stdc++.h>
using namespace std;
int N,K;
map<string,int> strtonum;
map<int,string> numtostr;
map<string,int> TotalFee;
int edge[2005][2005];
bool f[2005];
int cnt = 0;
int maxn = -1;
void DFS(int u,int &gang,int &groupnum,int &total){
if(TotalFee[numtostr[u]]>maxn){
maxn = TotalFee[numtostr[u]];
gang = u;
}
for(int i=0;i<cnt;i++){
if(edge[i][u]){
total += edge[i][u];
edge[i][u] = edge[u][i] = 0;
if(!f[i]){
f[i] = true;
groupnum++;
DFS(i,gang,groupnum,total);
}
}
}
}
map<string,int> mp;
int main(){
scanf("%d%d",&N,&K);
for(int i=0;i<N;i++){
string s1;
string s2;
int t;
cin >> s1 >> s2 >> t;
if(strtonum.find(s1)==strtonum.end()){
strtonum[s1] = cnt;
numtostr[cnt] = s1;
cnt++;
}
if(strtonum.find(s2)==strtonum.end()){
strtonum[s2] = cnt;
numtostr[cnt] = s2;
cnt++;
}
TotalFee[s1] += t;
TotalFee[s2] += t;
edge[strtonum[s1]][strtonum[s2]] += t;
edge[strtonum[s2]][strtonum[s1]] += t;
}
for(int i=0;i<cnt;i++){
int gang,groupnum = 1,totaledge = 0;
maxn = -1;
if(!f[i]){
f[i] = true;
DFS(i,gang,groupnum,totaledge);
if(totaledge>K && groupnum>2){
mp[numtostr[gang]] = groupnum;
}
}
}
int res = mp.size();
printf("%d\n",res);
for(auto it=mp.begin();it!=mp.end();it++){
printf("%s %d\n",it->first.c_str(),it->second);
}
return 0;
}
1035 Password (20 分)
算法标签: 字符串
#include<bits/stdc++.h>
using namespace std;
struct team{
string name;
string p;
};
team t[10005];
int main(){
int M;
scanf("%d",&M);
int cnt = 0;
for(int i=0;i<M;i++){
string name;
string password;
cin >> name >> password;
bool f = false;
for(int j=0;j<password.size();j++){
if(password[j] == '1'){
password[j] = '@';
f = true;
}else if(password[j] == 'O'){
password[j] = 'o';
f = true;
}else if(password[j] == 'l'){
password[j] = 'L';
f = true;
}else if(password[j] =='0'){
password[j] = '%';
f = true;
}
}
if(f){
t[cnt].name = name;
t[cnt++].p = password;
}
}
if(cnt){
cout << cnt << endl;
for(int i=0;i<cnt;i++){
cout << t[i].name << " " << t[i].p << endl;
}
}else{
if(M == 1){
cout << "There is 1 account and no account is modified" << endl;
}else{
cout << "There are "<< M <<" accounts and no account is modified" << endl;
}
}
return 0;
}
1036 Boys vs Girls (25 分)
算法标签: 排序
#include<bits/stdc++.h>
using namespace std;
int main(){
int M;
cin >> M;
string m_name;
string f_name;
string m_course;
string f_course;
int m_score = 101;
int f_score = -1;
for(int i=0;i<M;i++){
string s;
cin >> s;
string sex;
cin >> sex;
string course;
cin >> course;
int score;
cin >> score;
if(sex == "M"){
if(score<=m_score){
m_score = score;
m_name = s;
m_course = course;
}
}else{
if(score >= f_score){
f_score = score;
f_name = s;
f_course = course;
}
}
}
if(m_score == 101 && f_score == -1){
cout << "Absent" << endl
<< "Absent" << endl
<< "NA" ;
}else if(f_score == -1){
cout << "Absent" << endl
<< m_name << " " << m_course << endl << "NA";
}else if(m_score == 101){
cout << f_name << " " << f_course << endl
<< "Absent" << endl << "NA" ;
}else{
cout << f_name << " " << f_course << endl
<< m_name << " " << m_course << endl << f_score-m_score;
}
return 0;
}
1037 Magic Coupon (25 分)
算法标签: 排序 + 贪心
注意点: 最大值一定是负数和负数相乘+正数和正数相乘,且两数相对差越小,乘积越大:
a
∗
b
+
c
∗
d
>
=
a
∗
c
+
b
∗
d
,
a
>
=
b
>
=
c
>
=
d
a*b+c*d>=a*c+b*d,a>=b>=c>=d
a∗b+c∗d>=a∗c+b∗d,a>=b>=c>=d
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int b[maxn];
long long sum = 0;
int main(){
int NC,NP;
scanf("%d",&NC);
for(int i=0;i<NC;i++){
scanf("%d",&a[i]);
}
scanf("%d",&NP);
for(int i=0;i<NP;i++){
scanf("%d",&b[i]);
}
sort(a,a+NC);
sort(b,b+NP);
for(int i=0,j=0;i<min(NC,NP);i++,j++){
if(a[i]<0 && b[j]<0){
sum += a[i] * b[j];
}else{
break;
}
}
for(int i=NC-1,j=NP-1;i>=0 && j>=0;i--,j--){
if(a[i]>0 && b[j]>0){
sum += a[i]*b[j];
}else{
break;
}
}
printf("%lld\n",sum);
return 0;
}
1038 Recover the Smallest Number (30 分)
算法标签: 贪心 + 字符串
注意点: 生成字典序最小的字符串必须满足局部子式
s
1
s
2
<
s
2
s
1
s_1s_2<s_2s_1
s1s2<s2s1
#include<bits/stdc++.h>
using namespace std;
string s[10005];
bool cmp(string s1,string s2){
return s1+s2 < s2+s1;
}
int main(){
int N;
scanf("%d",&N);
for(int i=0;i<N;i++){
cin >> s[i];
}
sort(s,s+N,cmp);
string ans = "";
for(int i=0;i<N;i++){
ans += s[i];
}
int len = ans.size();
bool f = false;
for(int i=0;i<len;i++){
if(!f && ans[i]=='0'){
continue;
}else{
f = true;
printf("%c",ans[i]);
}
}
if(!f){
printf("0\n");
}
return 0;
}
1039 Course List for Student (25 分)
算法标签: 排序
#include<bits/stdc++.h>
using namespace std;
const int maxn = 26*26*26*10 + 5;
vector<int> hashT[maxn];
int hash1(char s[]){
int id = 0;
for(int i=0;i<3;i++){
id = id * 26 + s[i] - 'A';
}
id = id *10 + s[3]-'0';
return id;
}
int main(){
int N,K;
cin.tie(0);
cout.tie(0);
scanf("%d%d",&N,&K);
for(int i=0;i<K;i++){
int index,n;
scanf("%d%d",&index,&n);
for(int j=0;j<n;j++){
char s1[10];
scanf("%s",s1);
int id = hash1(s1);
hashT[id].push_back(index);
}
}
for(int i=0;i<N;i++){
char s1[10];
scanf("%s",s1);
int id = hash1(s1);
printf("%s %d",s1,hashT[id].size());
sort(hashT[id].begin(),hashT[id].end());
vector<int>::iterator it;
for(it = hashT[id].begin();it!=hashT[id].end();it++){
printf(" %d",*it);
}
printf("\n");
}
return 0;
}
1040 Longest Symmetric String (25 分)
算法标签: DP
注意点: 动态规划求最长回文子串的题目,可得初始条件如下:
设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示从第i个字符到第j个字符为回文串,那么
d
p
[
i
]
[
i
]
=
1
,
L
=
1
dp[i][i]=1,L=1
dp[i][i]=1,L=1
d
p
[
i
]
[
i
+
1
]
=
1
,
s
[
i
]
=
=
s
[
i
+
1
]
,
L
=
2
dp[i][i+1]=1,s[i]==s[i+1],L=2
dp[i][i+1]=1,s[i]==s[i+1],L=2
d
p
[
i
]
[
j
]
=
1
,
d
p
[
i
+
1
]
[
j
−
1
]
=
1
且
s
[
i
]
=
=
s
[
j
]
,
L
>
=
3
dp[i][j]=1,dp[i+1][j-1]=1且s[i]==s[j],L>=3
dp[i][j]=1,dp[i+1][j−1]=1且s[i]==s[j],L>=3
#include<bits/stdc++.h>
using namespace std;
int dp[1005][1005];
int main(){
string s;
getline(cin,s);
int len = s.size();
int ans = 1;
for(int i=0;i<len;i++){
dp[i][i] = 1;
if(i>=1 && s[i-1]==s[i]){
dp[i-1][i] = 1;
ans = 2;
}
}
for(int i=3;i<=len;i++){
for(int j=0;j<len-i+1;j++){
int k = j+i-1;
if(s[k] == s[j] && dp[j+1][k-1]==1){
dp[j][k] = 1;
ans = i;
}
}
}
cout << ans << endl;
return 0;
}
1041 Be Unique (20 分)
算法标签: 哈希
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int hashT[10005];
int main(){
int N;
scanf("%d",&N);
for(int i=0;i<N;i++){
scanf("%d",&a[i]);
hashT[a[i]] ++;
}
for(int i=0;i<N;i++){
if(hashT[a[i]]==1){
printf("%d\n",a[i]);
return 0;
}
}
printf("None\n");
return 0;
}
1042 Shuffling Machine (20 分)
算法标签: 模拟
注意点: 模拟混洗序列,核心公式为
c
[
b
[
j
]
]
=
a
[
j
]
;
c[b[j]] = a[j];
c[b[j]]=a[j];
#include<bits/stdc++.h>
using namespace std;
int a[105];
int b[105];
int c[105];
string s = "SHCDJ";
int main(){
int K;
cin >> K;
for(int i=1;i<=54;i++){
a[i] = i;
}
for(int i=1;i<=54;i++){
cin >> b[i];
}
for(int i=1;i<=K;i++){
for(int j=1;j<=54;j++){
c[b[j]] = a[j];
}
for(int j=1;j<=54;j++){
a[j] = c[j];
}
}
for(int i=1;i<=54;i++){
cout << s[(a[i]-1)/13];
cout << (a[i]-1) % 13 + 1;
if(i!=54){
cout << " ";
}else{
cout << endl;
}
}
return 0;
}
1043 Is It a Binary Search Tree (25 分)
算法标签: 树,二叉树 + 遍历
注意点: 所谓的镜像树,其实就是指颠倒了左右子树的访问顺序,其它条件都不变,因此,本题实质上依然是考察建树+遍历
#include<bits/stdc++.h>
using namespace std;
vector<int> pre,preM,post,postM,origin;
int N;
struct node{
int data;
node* lchild;
node* rchild;
};
node* root = NULL;
void insert(node* &root,int x){
if(root==NULL){
node *Node = new node;
Node->data = x;
Node->lchild = NULL;
Node->rchild = NULL;
root = Node;
return;
}
if(x<root->data){
insert(root->lchild,x);
}else{
insert(root->rchild,x);
}
}
int cnt = 0;
void PreOrder(node* root,vector<int> &pre){
if(root==NULL){
return;
}
pre.push_back(root->data);
PreOrder(root->lchild,pre);
PreOrder(root->rchild,pre);
}
void MirrorOrder(node *root,vector<int> &preM){
if(root==NULL){
return;
}
preM.push_back(root->data);
MirrorOrder(root->rchild,preM);
MirrorOrder(root->lchild,preM);
}
void PostOrder(node* root,vector<int> &post){
if(root==NULL){
return;
}
PostOrder(root->lchild,post);
PostOrder(root->rchild,post);
post.push_back(root->data);
}
void PostOrder1(node* root,vector<int> &postM){
if(root==NULL){
return;
}
PostOrder1(root->rchild,postM);
PostOrder1(root->lchild,postM);
postM.push_back(root->data);
}
int main(){
cin >> N;
for(int i=0;i<N;i++){
int t;
cin >> t;
origin.push_back(t);
insert(root,t);
}
PreOrder(root,pre);
MirrorOrder(root,preM);
if(pre==origin){
printf("YES\n");
PostOrder(root,post);
for(int i=0;i<post.size();i++){
if(i==0){
printf("%d",post[i]);
}else{
printf(" %d",post[i]);
}
}
}else if(preM==origin){
printf("YES\n");
PostOrder1(root,postM);
for(int i=0;i<postM.size();i++){
if(i==0){
printf("%d",postM[i]);
}else{
printf(" %d",postM[i]);
}
}
}else{
printf("NO\n");
}
return 0;
}
1044 Shopping in Mars (25 分)
算法标签: 模拟 + 二分
注意点: 先二分求最小间距,然后二分遍历求数对
(
a
,
b
)
(a,b)
(a,b)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int sum[maxn];
int main(){
int N,M;
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++){
scanf("%d",&a[i]);
sum[i] = sum[i-1] + a[i];
}
int minS =INT_MAX;
for(int i=1;i<=N;i++){
int pos = upper_bound(sum+1,sum+N+1,sum[i-1]+M)-sum;
if(sum[pos-1]-sum[i-1]==M){
minS = M;
break;
}else if(sum[pos]-sum[i-1]>M){
minS = min(minS,sum[pos]-sum[i-1]);
}
}
for(int i=1;i<=N;i++){
int pos = upper_bound(sum+1,sum+N+1,sum[i-1]+minS)-sum;
if(sum[pos-1]-sum[i-1]==minS){
printf("%d-%d\n",i,pos-1);
}
}
return 0;
};
1045 Favorite Color Stripe (30 分)
算法标签: DP
注意点: 最长不降子序列(LIS),状态转移方程为:
d
p
[
j
]
=
m
a
x
(
d
p
[
j
]
,
d
p
[
i
]
+
1
)
,
i
<
j
dp[j]=max(dp[j],dp[i]+1),i<j
dp[j]=max(dp[j],dp[i]+1),i<j
#include<bits/stdc++.h>
using namespace std;
bool flag[205];
int hashT[205];
int a[10005];
int dp[10005];
int main(){
int N;
scanf("%d",&N);
int M;
scanf("%d",&M);
for(int i=0;i<M;i++){
int t;
scanf("%d",&t);
if(!flag[t]){
hashT[t] = i;
flag[t] = true;
}
}
int L;
scanf("%d",&L);
int cnt = 0;
for(int i=0;i<L;i++){
int t;
scanf("%d",&t);
if(flag[t]){
a[cnt++] = t;
}
}
for(int i=0;i<cnt;i++){
dp[i] = 1;
for(int j=0;j<i;j++){
if(hashT[a[j]] <= hashT[a[i]]){
dp[i] = max(dp[i],dp[j]+1);
}
}
}
int maxn = -1;
for(int i=0;i<cnt;i++){
maxn = max(maxn,dp[i]);
}
cout << maxn << endl;
return 0;
}
1046 Shortest Distance (20 分)
算法标签: 模拟 + 前缀和
注意点: 求前缀和数组(预处理),查询输出
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int sum[maxn];
int main(){
int N;
cin >> N;
for(int i=1;i<=N;i++){
cin >> a[i];
sum[i] = sum[i-1] + a[i];
}
int cnt = sum[N];
int M;
cin >> M;
for(int i=1;i<=M;i++){
int s1,s2;
cin >> s1 >> s2;
if(s1>s2){
swap(s1,s2);
}
int res;
res = min(sum[s2-1]-sum[s1-1],cnt-(sum[s2-1]-sum[s1-1]));
cout << res << endl;
}
return 0;
}
1047 Student List for Course (25 分)
算法标签: 排序
#include<bits/stdc++.h>
using namespace std;
vector<int> hashT[2505];
int hash1(char s[]){
int id = 0;
for(int i=0;i<3;i++){
id = id * 26 + s[i] -'A';
}
id = id * 10 + s[3] -'0';
return id;
}
char s2[10];
void rhash(int id,char s[]){
s[3] = id % 10 + '0';
id/=10;
int j = 2;
while(j+1){
s[j--] = id % 26+ 'A';
id /= 26;
}
s[4] = '\0';
}
int main(){
int N,K;
scanf("%d%d",&N,&K);
for(int i=0;i<N;i++){
char s1[10];
scanf("%s",s1);
int id = hash1(s1);
int t;
scanf("%d",&t);
for(int j=0;j<t;j++){
int p;
scanf("%d",&p);
hashT[p].push_back(id);
}
}
for(int i=1;i<=K;i++){
printf("%d %d\n",i,hashT[i].size());
vector<int>::iterator it;
sort(hashT[i].begin(),hashT[i].end());
for(it = hashT[i].begin();it!=hashT[i].end();it++){
rhash(*it,s2);
printf("%s\n",s2);
}
}
return 0;
}
1048 Find Coins (25 分)
算法标签: 哈希 + two pointers
注意点: 双指针问题,从前到后枚举每个数,考察其和为M的另一个数是否存在,是就输出结果,注意特判两数相等的情形
#include<bits/stdc++.h>
using namespace std;
int a[10005];
int main(){
int N,M;
scanf("%d%d",&N,&M);
for(int i=0;i<N;i++){
int t;
scanf("%d",&t);
a[t]++;
}
for(int i=0;i<=M/2;i++){
if(i == M/2 && 2*i==M){
if(a[i]>=2){
printf("%d %d\n",i,M-i);
return 0;
}
}else{
if(a[i]>=1 && a[M-i]>=1){
printf("%d %d\n",i,M-i);
return 0;
}
}
}
printf("No Solution\n");
return 0;
}
1049 Counting Ones (30 分)
算法标签: 数论
注意点: 一道好题!求1的数量,我们可以将数字分成3个部分,左中右,中间的是当前正在处理的数字,可分为3类:
<
1
∣
=
1
∣
>
1
<1|=1|>1
<1∣=1∣>1
1.
=
0
(
<
1
)
:
a
n
s
+
=
l
e
f
t
∗
a
=0(<1):ans+=left*a
=0(<1):ans+=left∗a
2.
=
1
:
a
n
s
+
=
l
e
f
t
∗
a
+
r
i
g
h
t
+
1
=1:ans+=left*a+right+1
=1:ans+=left∗a+right+1
3.
>
1
:
a
n
s
+
=
(
l
e
f
t
+
1
)
∗
a
>1:ans+=(left+1)*a
>1:ans+=(left+1)∗a
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
scanf("%d",&n);
int n1 = n;
int cnt = 0;
while(n1){
n1/=10;
cnt++;
}
int p = 1;
long long sum = 0;
for(int i=0;i<cnt;i++){
int left = n/p/10;
int now = n/p%10;
int right = n%p;
if(now==0){
sum += (left*p);
}else if(now==1){
sum += (left*p + right +1);
}else{
sum += (left+1)*p;
}
p*=10;
}
printf("%lld\n",sum);
return 0;
}
1050 String Subtraction (20 分)
算法标签: 字符串
#include<stdio.h>
#include<string.h>
#include<stdbool.h>
bool hashT[256];
char s1[10005];
char s2[10005];
int main(){
gets(s1);
gets(s2);
int len1 = strlen(s1);
int len2 = strlen(s2);
for(int i=0;i<len2;i++){
hashT[s2[i]] = true;
}
for(int i=0;i<len1;i++){
if(!hashT[s1[i]]){
printf("%c",s1[i]);
}
}
printf("\n");
return 0;
}