题目链接
A. Watermelon
B. Before an Exam
C. Registration system
D. Mysterious Present
题目描述
A. Watermelon
给定一个数
w
w
w,能否将这个
w
w
w 分成两个偶数。可以就打印 YES
,否则打印 NO
。
输入
8
输出
YES
数据范围
- 1 ≤ w ≤ 100 1 ≤ w ≤ 100 1 ≤ w ≤ 100
分析: 只需要简单的分类讨论即可。
时间复杂度: O ( 1 ) O(1) O(1)
代码:
#include<iostream>
using namespace std;
int w;
int main(){
scanf("%d",&w);
if(w&1 || w==2){
cout<<"NO"<<endl;
}
else cout<<"YES"<<endl;
return 0;
}
B. Before an Exam
给定一个数 n n n 代表一共有 n n n 天,在给定一个 s u m sum sum,代表共有 s u m sum sum 个小时可以分配。每一天能够分配的小时数量,最小是 a i a_i ai,最大是 b i ( 1 < = i < = n ) b_i(1<=i<=n) bi(1<=i<=n)。
问能否在这 n n n 天的每一天都分配一定的小时数, s u m sum sum小时必须用完。
可以就打印 YES
,并输出具体每一天分配的小时数;否则就打印 NO
。
输入
1 48
5 7
输出
NO
输入
2 5
0 1
3 5
输出
YES
1 4
数据范围
- 1 ≤ n ≤ 30 1 ≤ n ≤ 30 1 ≤ n ≤ 30
- 0 ≤ s u m ≤ 240 0 ≤ sum≤ 240 0 ≤ sum≤ 240
- 0 ≤ a i ≤ b i ≤ 8 0 ≤ a_i≤ b_i ≤ 8 0 ≤ ai≤ bi ≤ 8
分析:
贪心的考虑:
- 如果 sum < 最小的分配数 或者 sum > 最大分配数,都不能满足要求,直接打印
NO
。 - 否则,每一天都先分配最小的小时数,然后再遍历将剩余的小时数量用完即可。
时间复杂度: O ( n ) O(n) O(n)
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
const int N = 40;
int a[N],b[N];
int f[N];
int main(){
int n,sum;
scanf("%d%d",&n,&sum);
int mi = 0,ma = 0;
for(int i = 1;i <= n;i++){
scanf("%d%d",&a[i],&b[i]);
mi += a[i],ma += b[i];
f[i] = a[i];
}
//不可能成功分配的,直接打印 NO,结束程序
if(sum < mi || sum > ma){
puts("NO");
return 0;
}
//每一天先分配最小的时间
sum -= mi;
for(int i = 1;i <= n && sum;i++){
int d = b[i] - a[i];
if(sum <= d){
f[i] += sum;
sum = 0;
}
else{
f[i] += d;
sum -= d;
}
}
puts("YES");
for(int i = 1;i <= n;i++) printf("%d ",f[i]);
return 0;
}
C. Registration system
设计一个注册系统,给定你一些 字符串(用户名)进行注册。
如果该用户名 name 没有在系统中注册过,返回OK
。
否则就返回 “name1 name2 name3...”
。
输入
4
abacaba
acaba
abacaba
acab
输出
OK
OK
abacaba1
OK
输入
7
first
first
second
second
third
third
third
输出
OK
first1
OK
second1
OK
third1
third2
数据范围
- 1 ≤ n ≤ 1 0 5 1 ≤ n ≤ 10^5 1 ≤ n ≤ 105
分析:
直接用一个哈希表记录相同字符串的次数,模拟即可。
时间复杂度: O ( n ) O(n) O(n)
代码:
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstring>
#include<unordered_map>
using namespace std;
const int N = 40;
int main(){
int n;
scanf("%d%d",&n);
unordered_map<string,int> cnt;
for(int i = 1;i <= n;i++){
string s;
getline(cin,s);
if(!cnt.count(s)){
cnt[s]++;
puts("OK");
}
else{
cnt[s]++;
s += to_string(cnt[s] - 1);
cout<<s<<endl;
}
}
return 0;
}
}
D. Mysterious Present
给你一张卡片,这张卡片 长 h h h ,宽 w w w。
在给你一些信封,这些信封 长 h i h_i hi,宽 w i w_i wi。
大的信封才可以包小的,信封不能旋转,并且其中最小的信封也能包住卡片,卡片也不能旋转。
求最多能套多少张信封,以及具体是哪些信封(打印信封的序号,从1开始)
输入格式
信封的张数n 卡片宽度w 卡片长度h
第一张信封的宽度w1 第一张信封的长度h1
第二张信封的宽度w2 第二张信封的长度h2
…
输出格式
满足要求的最大信封张数
具体是哪些信封(按照宽,高,从小大大排序)
输入
2 1 1
2 2
2 2
输出
1
1
输入
3 3 3
5 4
12 11
9 8
输出
3
1 3 2
数据范围
- 1 ≤ n ≤ 5000 1 ≤ n ≤ 5000 1 ≤ n ≤ 5000
- 1 ≤ w , h ≤ 106 1 ≤ w, h ≤ 106 1 ≤ w, h ≤ 106
- 1 ≤ w i , h i ≤ 106 1 ≤ w_i, h_i ≤ 106 1 ≤ wi, hi ≤ 106
分析:
这道题就是 最长上升子序列模型的一个变形。
最长上升子序列:最长递增子序列
在输入数据的时候,我们只记录比卡片大的信封(比卡片长,比卡片宽)。
然后我们在对其进行排序(先按宽度排序,再按长度排序)。
我们定义 f ( i ) f(i) f(i) 是以第 i 个信封结尾的最大信封数量,再定义 p r e ( i ) pre(i) pre(i) 是从哪一个状态转移过来的(方便我们打印具体是哪些信封)。
在DP的过程中不断更新最大长度,然后我们再旋转其中的一条长度最大的信封序列打印输出。
时间复杂度: O ( n 2 ) O(n^2) O(n2)
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
const int INF=0x3f3f3f3f,N=5005;
int f[N],pre[N];
struct node
{
int w,h,id;
bool operator<(const node &b)const
{
if(w==b.w)return h<b.h;
return w<b.w;
}
}a[N];
int main()
{ int n,w,h;
int m = 0;
scanf("%d%d%d",&n,&w,&h);
for(int i=1;i<=n;i++)
{
int ww,hh;
scanf("%d%d",&ww,&hh);
//只记录大于 卡片 的信封信息
if(ww>w&&hh>h)a[++m]=(node){ww,hh,i};
}
//m == 0 说明没有打于 卡片的信封,直接输出0
if(m==0)printf("0\n");
else
{
sort(a+1,a+m+1);
f[0]=0;
for(int i=1;i<=m;i++)
{
int pos=0;
for(int j=1;j<i;j++)
//后面的信封必须 长和宽 都比前面的信封大才行
if(a[j].w<a[i].w&&a[j].h<a[i].h)
if(f[j]>f[pos])pos=j;
f[i]=f[pos]+1;
pre[i]=pos;
}
//找长度最大的信封序列
int pos=1;
for(int i=1;i<=m;i++)
if(f[i]>f[pos])pos=i;
printf("%d\n",f[pos]);
//此时的pos是终点,需要根据 pre 去不断的找前面的点,直到找到起点为止
vector<int>ans;
while(pos)
{
ans.push_back(a[pos].id);
pos=pre[pos];
}
for(int i=ans.size()-1;i>=0;i--) printf("%d ",ans[i]);
}
return 0;
}