C. Exams
思路:贪心。按考试时间排个序,优先排ai,若相等排bi。然后从头到尾扫一遍,得出最小值。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctype.h>
#include <sstream>
#define INF 1000000000
#define ll long long
#define min3(a,b,c) min(a,min(b,c))
#define max3(a,b,c) max(a,max(b,c))
using namespace std;
struct ex{
int a;
int b;
};
ex e[5050];
bool cmp(ex a,ex b){
if(a.a!=b.a){
return a.a<b.a;
}
return a.b<b.b;
}
int main(){
int n;
while(cin>>n){
for(int i=1;i<=n;i++){
cin>>e[i].a>>e[i].b;
}
sort(e+1,e+n+1,cmp);
int ans=0;
for(int i=1;i<=n;i++){
int _min=min(e[i].a,e[i].b);
int _max=max(e[i].a,e[i].b);
if(_min>=ans){
ans=_min;
}else{
ans=_max;
}
}
cout<<ans<<endl;
}
return 0;
}
D. Long Jumps
思路:二分搜索/平衡搜索树(直接用set)。把尺子的每个刻度放到集合里,对每个刻度ai,查找ai+x和ai+y是否存在。如果不存在,测试是否能只添加一个刻度解决,如果不能,直接添加两个刻度。
具体地说,如果原来就存在ai+x和ai+y中的一个,直接添加y/x就可以。如果都不存在,则需要测试ai±x±y是否存在。此题有坑:注意加的刻度不要溢出尺子的范围。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctype.h>
#include <sstream>
#define INF 1000000000
#define ll long long
#define min3(a,b,c) min(a,min(b,c))
#define max3(a,b,c) max(a,max(b,c))
using namespace std;
int main(){
ll n,l,x,y;
set<ll> Set;
while(cin>>n>>l>>x>>y){
for(int i=1;i<=n;++i){
ll t;
scanf("%I64d",&t);
Set.insert(t);
}
bool checkx=0;
bool checky=0;
for(set<ll>::iterator it=Set.begin();it!=Set.end();it++){
if( Set.find(*it+x)!=Set.end() ){
checkx=1;
}
if( Set.find(*it+y)!=Set.end() ){
checky=1;
}
if(checkx&&checky){
break;
}
}
if(checkx&&checky){
cout<<0<<endl;
break;
}
if(checkx){
cout<<1<<endl;
cout<<y<<endl;
break;
}
if(checky){
cout<<1<<endl;
cout<<x<<endl;
break;
}
bool find=0;
ll ans=0;
for(set<ll>::iterator it=Set.begin();it!=Set.end();it++){
if( (*it+x<=l)&&Set.find(*it+x+y)!=Set.end() ){
find=1;
ans=*it+x;
break;
}
if( (*it+x<=l)&&Set.find(*it+x-y)!=Set.end() ){
find=1;
ans=*it+x;
break;
}
if( (*it-x>=0)&&Set.find(*it-x+y)!=Set.end() ){
find=1;
ans=*it-x;
break;
}
if( (*it-x>=0)&&Set.find(*it-x-y)!=Set.end() ){
find=1;
ans=*it-x;
break;
}
}
if(find){
cout<<1<<endl;
cout<<ans<<endl;
break;
}
cout<<2<<endl;
cout<<x<<" "<<y<<endl;
}
return 0;
}
E. Riding in a Lift
思路:DP(滚动数组)。dp(i,j)表示第 imod2 次转移后,走到j层有多少种方法。
DP是很容易想到的,但是也很容易认为转移的复杂度是O(n)而放弃这个想法。其实转移的复杂度可以看成是O(1),这就需要一些小技巧。在状态转移的时候需要求区间和,我们可以先求一遍最大区间的和,边转移边维护区间的范围。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctype.h>
#include <sstream>
#define INF 1000000000
#define ll long long
#define min3(a,b,c) min(a,min(b,c))
#define max3(a,b,c) max(a,max(b,c))
using namespace std;
const int mod=1E9+7;
int n,a,b,k;
int dp[2][5010];
int main(){
while(cin>>n>>a>>b>>k){
if(a>b){
a=1+(n-a);
b=1+(n-b);
}
dp[0][a]=1;
for(int i=1;i<=k;i++){
for(int j=j;j<=b-1;j++)dp[i%2][j]=0;
int sum=0;
for(int j=1;j<=b-1;j++){
sum+=dp[(i-1)%2][j];
sum%=mod;
}
int test=b-1;
for(int j=b-1;j>=1;j--){
sum-=dp[(i-1)%2][j];
sum+=mod;
sum%=mod;
dp[i%2][j]=sum;
sum+=dp[(i-1)%2][j];
sum%=mod;
if(b-test<=test-(j-1) ){//测试是否需要缩小区间
if(test!=(j-1) ){
sum-=dp[(i-1)%2][test];
sum+=mod;
sum%=mod;
test--;
}
}
}
}
int ans=0;
for(int i=1;i<b;i++){
ans+=dp[k%2][i];
ans%=mod;
}
cout<<ans<<endl;
}
return 0;
}