五一补题

7-5 田忌赛马·Hard

先同easy版对比一下:

7-4 田忌赛马·Easy

解决方法:对两组进行排序,如果a[n-i-1]>b[k-i-1],则k++;

 

解题思路:——二分

根据题目可知,我们寻找的是从某一天开始a中的🐎至少获胜k场,那么在这一天之前获胜场数一定是小于k,根据这种性质(类似于单调性)我们可以判断我们设定的第M天是在答案天数的左侧还是右侧,从而可以利用二分解决这个问题。

蒟蒻的代码: 

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e8;
int t,k,n;
struct pp{
    int a;
    int aa;
}p[11000];
int b[11000];
int check(int mid){
    vector<int>v;
    for(int i=0;i<n;i++) v.push_back(p[i].a+p[i].aa*mid);
    sort(v.begin(),v.end());
    int kk=0;
    int num=0;
    for(int i=0;i<k;i++){
        if(v[n-i-1]>b[k-i-1])
            kk++;
    }
    if(kk>=k) return 1;
    return 0;
}
signed main(){
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--){
        cin>>n>>k;
        for(int i=0;i<n;i++) cin>>p[i].a>>p[i].aa;
        for(int i=0;i<n;i++) cin>>b[i];
        int l = 0, r = N;
        sort(b,b+n);
        if(!check(r)) cout<<-1<<endl;
        else{
            while(l<r){
            int mid=(l+r)/2;
            if(check(mid)) r=mid;
            else l=mid+1;
        }
        cout<<l<<endl;
        }
    }
    return 0;
}

注意考虑不能改变a中🐎的初始速度,照常搬运y总二分模板就可以ac了(y总牛批)

 侯学长的代码:(我的stl还是不行啊/(ㄒoㄒ)/~~)

#include <bits/stdc++.h>

#define int long long
#define a first
#define b second
using namespace std;
const int N = 10010;
int t, n, k;
pair<int, int>my[N];
int op[N];

bool check(int mid) {
    int win = 0, idx = 0;
    vector<int>cur;
    for (int i = 0;i < n; i++) cur.push_back(my[i].a + my[i].b * mid);
    sort(cur.begin(), cur.end(), greater<int>());
    for (int i = 0;i < n; i++) {
        if (cur[idx] > op[i]) idx++, win++;
    }
    return win >= k;
}

signed main() {
    scanf("%lld", &t);
    while (t--) {
        scanf("%lld %lld", &n, &k);
        for (int i = 0;i < n; i++) scanf("%lld %lld", &my[i].a, &my[i].b);
        for (int i = 0;i < n; i++) scanf("%lld", &op[i]);
        int l = -1, r = 0x3f3f3f3f;
        sort(op, op + n, greater<int>());
        if (!check(r)) puts("-1");
        else {
            while (r - l != 1) {
                int mid = (l + r) / 2;
                if(check(mid)) r = mid;
                else l = mid;
            }
            printf("%lld\n", r);
        }
    }
    return 0;
}

 

 

7-7 放置方案数

dp题/(ㄒoㄒ)/~~

  • 最多可以有连续两个盒子放相同颜色的球,所以只需要考虑连续的三个盒子即可
  • 用dp[i] [0]表示第 i 个盒子放和第 i−1 个盒子球颜色不同的球的方案数
  • 用dp[i] [1]表示第 i 个盒子放和第 i−1 个盒子球颜色相同的球的方案数
  • dp[i] [0] = (dp[i - 1] [0] + dp[i - 1] [1]) * (k - 1) % Mod;
  • dp[i] [1] = dp[i - 1] [0];

 

#include <bits/stdc++.h>

#define int long long
using namespace std;

int T, n, k;
int dp[100005][2];
const int Mod = 1e9 + 7;

signed main() {
    scanf("%lld", &T);
    while (T--) {
        scanf("%lld%lld", &n, &k);
        dp[1][0] = k;
        dp[1][1] = 0;
        for (int i = 2; i <= n; i++) {
            dp[i][0] = (dp[i - 1][0] + dp[i - 1][1]) * (k - 1) % Mod;
            dp[i][1] = dp[i - 1][0];
        }
        printf("%lld\n", (dp[n][0] + dp[n][1]) % Mod);
    }
    return 0;
}

 

 

7-6 搭帐篷

二维前缀和+二分,题解慢慢写吧。。。学长的代码确实妙啊

 

#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int L,W;
int a[N][N],s[N][N];

bool check(int mid){
    mid--;
    for(int i=1;i<=L-mid;i++){
        for(int j=1;j<=W-mid;j++){
            int x1=i,x2=i+mid,y1=j,y2=j+mid;
            if(s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]==0)
                return true;
        }
    }
    return false;
}

int main() {
    while(cin>>L>>W){
        if(!L&&!W) break;
        memset(a,0,sizeof(a));
        for(int i=1;i<=L;i++){
            for(int j=1;j<=W;j++){
                cin>>a[i][j];
                if(a[i][j]==1)
                    a[i][j]=0;
            }
        }

        for(int i=1;i<=L;i++){
            for(int j=1;j<=W;j++){
                s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1];
            }
        }
      /*  if(min(L,W)==1){
                int flag=0;
            for(int i=1;i<=L;i++){
                for(int j=1;j<=W;j++){
                    if(a[i][j]==0){
                        flag=1;
                    }
                }
            }
        if(!flag)
            cout<<0<<endl;
        else
            cout<<1<<endl;
        }*/
     //   else{
            int l=-1,r=min(L,W),ans=0;
        while(l<r){
            int mid= l+r+1 >>1;
            if(check(mid)){
                l=mid;
                ans=mid;
            }
            else r=mid-1;
        }
        cout<<ans*ans<<endl;
     //   }
    }
    return 0;
}

 

 

7-4 螺旋矩阵

模拟,这个题写不出应该回炉重造C语言

这个题最难过的点就是输出——如何正确输出模拟后的螺旋:

  1. 因为无法判断字符最后的落点,所以使用从里往外旋的方法比较简单
  2. 必须按字符串一行一行输出(暂时没有更好的方法),不能一个一个字符输出,因为最后一个字符的落点不能判断,所以无法判断每一行是否有正好ey-by+1个字符,而直接输出一行可以避免这个问题
  3. 注意每个矩阵之间有一个空行
#include<bits/stdc++.h>
using namespace std;
char c[1100][1100];
string s;
int t;
int main(){
    cin>>t;
    getchar();
    while(t--){
        cin>>s;
        memset(c,0,sizeof(c));
        int x=500,y=500,v=4;
        for(int i=0;i<s.size();i++){
            c[x][y]=s[i];
            if(v==1){
                if(c[x-1][y]==0) v=3,x--;
                else y++;
            }else if(v==2){
                if(c[x+1][y]==0) v=4,x++;
                else y--;
            }else if(v==3){
                if(c[x][y-1]==0) v=2,y--;
                else x--;
            }else if(v==4){
                if(c[x][y+1]==0) v=1,y++;
                else x++;
            }
        }
        int bx=500,by=500,ex=500,ey=500;
        for(int i=0;i<1000;i++){
            for(int j=0;j<1000;j++){
                if(c[i][j]!=0){
                    if(i<bx) bx=i;
                    if(i>ex) ex=i;
                    if(j>ey) ey=j;
                    if(j<by) by=j;
                }
            }
        }

        for(int i=bx;i<=ex;i++){
            for(int j=by;j<ey;j++){
                if(c[i][j]=='\0') c[i][j]=' ';
                else break;
            }
        }

        for(int i=bx;i<=ex;i++){
            cout<<c[i]+by<<endl;
        }
        cout<<endl;
    }
    return 0;
}

左上右下循环,每次判断下一种情况下的位置是否为0,若为0,转为下一种情况,否则继续该情况

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值