比赛的时候过了3题的pretest,结果systest怒跪2题。。rank几乎垫底。但是这场题目确实比较简单。
A. Road to Cinema
cf特别爱出的二分题。。二分汽油容量,得到一个最小的能跑完的容量,然后在满足这个最小值的车里面找最便宜的。注意可能全程加速也赶不上。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200010;
const ll INF = 1e18;
ll c[maxn];
ll v[maxn];
ll g[maxn];
ll n,k,s,t; //车数 加油站数 路程 时间
bool judge(ll x){
ll Time = 0;
for(int i=0;i<=k;i++){
ll distance = g[i+1] - g[i];
if(distance > x){
return 0;
}
ll tmp = x - distance;
tmp = min(distance,tmp);
Time += tmp + (distance-tmp)*2;
if(Time > t){
return 0;
}
}
if(Time > t){
return 0;
}else{
return 1;
}
}
ll bs(){
ll l = 1;
ll r = 4e9+10;
ll res = -1;
while(l<=r){
ll mid = (l+r)>>1;
if(judge(mid)){
res = mid;
r = mid - 1;
}else{
l = mid + 1;
}
}
return res;
}
int main(){
cin>>n>>k>>s>>t;
for(int i=1;i<=n;i++){
scanf("%I64d %I64d",&c[i],&v[i]);
}
for(int i=1;i<=k;i++){
scanf("%I64d",&g[i]);
}
sort(g+1,g+k+1);
g[0] = 0;
g[k+1] = s;
ll MIN = bs();
ll res = INF;
for(int i=1;i<=n;i++){
if(v[i]>=MIN){
res = min(res,c[i]);
}
}
if(res == INF || MIN == -1){ //注意有可能全程加速也不行
cout<<-1<<endl;
}else{
cout<<res<<endl;
}
return 0;
}
B. Sea Battle
贪心。我的写法是把所有船安排在尽可能靠右的位置,然后从左往右射击,这样就能模拟最坏情况。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
char s[200010];
int main(){
int n,a,b,k;
cin>>n>>a>>b>>k; //长度 个数 船长度
scanf("%s",s+1);
int cnt = 0;
int leftMost = -1;
int ship = 0;
for(int i=n;i>=1;i--){
if(s[i] == '0'){
cnt++;
}else{
cnt = 0;
}
if(cnt == b){
cnt = 0;
ship++;
}
if(ship == a){
leftMost = i;
break;
}
}
vector<int> hit;
cnt = 0;
int ans = 0;
for(int i=1;i<=n;i++){
if(s[i] == '0'){
cnt++;
}else{
cnt = 0;
}
if(cnt == b){
if(i<leftMost){
ans++;
hit.push_back(i);
cnt = 0;
}else{
ans++;
hit.push_back(i);
break;
}
}
}
cout<<ans<<endl;
for(int i=0;i<hit.size();i++){
printf("%d ",hit[i]);
}
return 0;
}
C. Subordinates
还是贪心。首先保证chief没有上司,然后统计上司个数为 i 的人数。然后要保证除了chief都有上司,即修改上司数为0的人,使得尽可能连续存在上司个数为0,1,2,3,…的人。然后枚举上司最多的人的上司数目,得到答案。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200010;
int a[maxn];
int f[maxn];
int miss[maxn];
int sum[maxn];
int main(){
int n,s;
cin>>n>>s;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int ans1 = 0;
if(a[s] != 0){
ans1 ++;
a[s] = 0;
}
int zero = 0;
for(int i=1;i<=n;i++){
f[a[i]] ++;
if(a[i] == 0){
zero ++;
}
}
zero--;
int i = 0;
while(zero--){
while(f[i]!=0){
i++;
}
f[0]--;
f[i]++;
ans1++;
}
sum[0] = 1;
for(int i=1;i<n;i++){
if(f[i] == 0){
miss[i] = miss[i-1] + 1;
}else{
miss[i] = miss[i-1];
}
sum[i] = sum[i-1] + f[i];
}
int ans2 = 1e9;
for(int i=n-1;i>=1;i--){ //枚举上司最多的人的上司数
int tmp = max( (n-sum[i]) , miss[i] );
ans2 = min(ans2,tmp);
}
if(n==1){
ans2 = 0;
}
cout<<ans1+ans2<<endl;
return 0;
}
D. Financiers Game
首先要正确理解题意,就是两个人都想让自己拿到的总数尽可能大。容易想到应当用dp来做。状态
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
#define ll long long
int n;
int a[4004];
int sum[4004];
bool vis[2080][70][70][2];
int dp[2080][70][70][2];
int getSum(int l,int r){
return sum[r] - sum[l-1];
}
int solve(int l,int R,int k,bool who){
int r;
if(who == 0){
r = n-l+1 -R;
}else{
r = n-l+1 +k-R;
}
if(r-l+1<k){
return 0;
}
if(vis[l][R][k][who]){
return dp[l][R][k][who];
}
vis[l][R][k][who] = 1;
int res;
if(who == 0){ //max
int t1 = solve(l+k,R,k,!who);
if(r-l+1>=k+1){
int t2 = solve(l+k+1,R,k+1,!who);
if( (-t1+getSum(l,l+k-1)) > (-t2+getSum(l,l+k)) ){
res = -t1+getSum(l,l+k-1);
}else{
res = -t2+getSum(l,l+k);
}
}else{
res = -t1+getSum(l,l+k-1);
}
}else{ //min
int t1 = solve(l,R,k,!who);
if(r-l+1>=k+1){
int t2 = solve(l,R+1,k+1,!who);
if( (-t1+getSum(r-k+1,r)) > (-t2+getSum(r-k,r)) ){
res = -t1+getSum(r-k+1,r);
}else{
res = -t2+getSum(r-k,r);
}
}else{
res = -t1+getSum(r-k+1,r);
}
}
dp[l][R][k][who] = res;
return res;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
sum[i] = sum[i-1] + a[i];
}
int ans = solve(1,0,1,0);
cout<<ans<<endl;
return 0;
}