每日做题1

平时总是懈怠,明明决定要认真做的事情一直拖延一直玩。所以在博客记录下来我一天做题的记录,这样或许能帮助我更好完成我的学习任务和学业。

8.9-8.19之间,每天完成三场div3的训练,补题数以一场两题为界限,如果两题内包含超过1900分分看知识点,如果知识点学过补,没学过不补。

8.9号的没记录,现在从8.10号的开始记录。

1.round 895 div3 1

a.Two Vessels

思路:贪心尧水

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin >> t;
    while(t--) 
    {
        int a,b,c;
        cin >> a >> b >> c;
        c*=2;
        int num=abs(a-b);
        cout << (num%c==0 ? num/c : num/c+1) << endl;
    }
    return 0;
}

2.The Corridor or There and Back Again

思路:贪心找到每一个陷阱的最远行驶距离然后取max

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin >> t;
    while(t--) {
        int n;
        cin >> n;
        int min_v=0x3f3f3f3f;
        for(int i=1;i<=n;i++) {
            int d,t;
            cin >> d >> t;
            min_v=min(min_v,d+(t-1)/2);
        }
        cout << min_v << endl;
    }
    return 0;
}

3.Non-coprime Split(补1)

思路:gcd有性质:gcd(a,b)若a>b有gcd(a-b,b)==gcd(a,b),所以我只要找到l到r范围里面是不是有一个数有因数,如果有那么我就可以通过构造 (因数,i-因数) 【i是有一个数的这个数】来构造我的一个正确解法。(代码里的偶数情况其实可以包含在这个解法里面)

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin >> t;
    while(t--) {
        int l,r;
        cin >> l >> r;
        bool flag=false;
        for(int i=l;i<=r;i++) {
            if(i%2==0 && i!=2) {
                flag=true;
                cout << 2 << " " << i-2 << endl;
                break;
            }else {
                for(int j=2;j*j<=i;j++) 
                {
                    if(i%j==0) {
                        if(i-j>=0) {
                            cout << j << " " << i-j << endl;
                            flag=true;
                            break;
                        }
                    }
                }
            }
            if(flag) break;
        }
        if(!flag) cout << -1 << endl;
    }
}

4.

因为cf崩了一个下午加一个晚上,计划失败

8.11

1.round 894 div3 2

a.Gift Carpet

找输入的数组里面是不是有从前往后四个不同列中分别有vike,暴力找就好了,但是我写的代码有点太暴力了,还好只有四个字母,题解给的代码和我的意思一样,但是pos的地方改成了如果成功累加其实这样能少写很多加快速度。

#include <bits/stdc++.h>
using namespace std;
const int N=25;
string S[N];
int main()
{
    int t;
    cin >> t;
    while(t--) {
        int n,m;
        cin >> n >> m;
        for(int i=1;i<=n;i++) {
            cin >> S[i];
        }
        bool pos1=0,pos2=0,pos3=0,pos4=0;
        for(int i=0;i<S[1].size();i++) {
            for(int j=1;j<=n;j++) {
                // cout << S[j][i] << endl;
                if(S[j][i]=='v' && !pos1) {
                    pos1=true;
                    break;
                }
                if(S[j][i]=='i' && pos1 && !pos2) {
                    pos2=true;
                    break;
                }
                if(S[j][i]=='k' && pos2 && !pos3) {
                    pos3=true;
                    break;
                }
                if(S[j][i]=='a' && pos3 && !pos4) {
                    cout << "YES" << endl;
                    pos4=true;
                    break;
                }
                if(pos4) break;
            }
        }
        if(!pos4) cout << "NO" << endl;
    }
    return 0;
}

b.Sequence Game

构造题,但是要注意范围,不能小于1,所以直接扫一遍如果比前面的数小vector插入一个自己就好了。

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int B[N];
int main()
{
    int t;
    cin >> t;
    while(t--) {
        int n;
        cin >> n;
        vector<int> A;
        for(int i=1;i<=n;i++) {
            cin >> B[i];
            if(B[i]<B[i-1]) {
                A.push_back(B[i]);
            }
            A.push_back(B[i]);
        }
        cout << A.size() << endl;
        for(auto t:A) {
            cout << t << " ";
        }
        cout << endl;
    }
}

c.Flower City Fence(补1)

其实是想到了,用差分,但是边界总是搞不清楚给自己搞晕了。就是输入的时候按照题意是一条条竖直的,然后可以对每一条竖直的进行差分,对差分数组前缀和后,每个B[i]存的就是对应i高度的厚度,然后再用这个厚度和我的原来A[i]数组比较看是不是相等就行。但是因为输入的时候我的A[i]的值是1e9非常容易爆我的f所以我应该特判一下。

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int A[N],S[N],B[N];
int main()
{
    int t;
    cin >> t;
    while(t--) {
        memset(S,0,sizeof S);
        memset(B,0,sizeof B);
        int n;
        cin >> n;
        bool flag=false;
        for(int i=1;i<=n;i++) {
            cin >> A[i];
            if(A[i]>n && !flag) {
                cout << "NO" << endl;
                flag=true;
            }
            S[1]++;
            if(!flag) S[A[i]+1]--;
        }

        if(flag) continue;
        // cout << "where:"  << flag << endl;

        for(int i=1;i<=n;i++) {
            B[i]=B[i-1]+S[i];
            // cout << "B:" << B[i] << endl;
        }

        for(int i=1;i<=n;i++) {
            if(A[i]!=B[i]) {
                cout << "NO" << endl;
                flag=true;
                break;
            }
        }
        if(!flag) cout << "YES" << endl;
    }
    return 0;
}

4.

2.round 820 div3 3

a和b都是裸贪心

c.Jumping on Tiles

要求给出头字母到尾字母中间的路径和花费(差值和距离),因为'a'->'c'和'a'->'b'->'c'相同花费,所以说尽可能多找两个字符的中间值。

我写的办法是开pair存值和i,排序后找到两个字母的左右区间然后输出出来,但是题目要求得从1开始结尾是|s|,这样导致我二分的边界有四个。我一开始没想这么多导致我即找不到错误在那里改了快一个小时。

还是尽可能能不二分不二分,官方题解采用的是找到左右两边界,用map存vector然后一个个找,这样特判找不容易错。

我的代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
typedef pair<int,int> PII;
const int N=2e5+10;
PII cnt[N];
int cnt1[N];
bool cmp(const PII &a,const PII &b) {
    if(a.x!=b.x) {
        return a.x<b.x;
    }else {
        return a.y<b.y;
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while(t--) {
        string s;
        cin >> s;
        for(int i=0;i<s.size();i++) {
            cnt[i]={s[i]+1-'a',i+1};
        }
        sort(cnt,cnt+s.size(),cmp);

        //复制到数组里用二分
        for(int i=0;i<s.size();i++) {
            cnt1[i]=cnt[i].x;
            // cout << "cnt:" << cnt[i].x << " ";
        }

        int l=s[0]+1-'a',r=s[s.size()-1]+1-'a';
        
        int n=s.size();

        if(l==r) {
            int rr;
            int ll=lower_bound(cnt1,cnt1+n,l)-cnt1;
            if(cnt[n-1].x!=r) rr=upper_bound(cnt1,cnt1+n,r)-1-cnt1;
            else rr=n-1;

            cout << r-l << " " << rr-ll+1 << endl; 
            for(int i=ll;i<=rr;i++) {
                cout << cnt[i].y << " ";
            }
            cout << endl;
        }else if(l<r) {
            int rr;
            int ll=lower_bound(cnt1,cnt1+n,l)-cnt1;
            if((cnt[n-1].x)!=r) rr=upper_bound(cnt1,cnt1+n,r)-1-cnt1;
            else rr=n-1;

            cout << r-l << " " << rr-ll+1 << endl; 
            for(int i=ll;i<=rr;i++) {
                cout << cnt[i].y << " ";
            }
            cout << endl;
        }else {
            int rr;
            int ll=lower_bound(cnt1,cnt1+n,r)-cnt1;
            int llr=upper_bound(cnt1,cnt1+n,r)-1-cnt1;
            if((cnt[n-1].x)!=l) 
            {
                rr=upper_bound(cnt1,cnt1+n,l)-1-cnt1;
            }
            else rr=n-1;

            int rrl=lower_bound(cnt1,cnt1+n,l)-cnt1;

            cout << abs(r-l) << " " << rr-ll+1 << endl; 
            for(int i=rrl;i<=rr;i++) {
                cout << cnt[i].y << " ";
            }
            for(int i=rrl-1;i>llr;i--) {
                cout << cnt[i].y << " ";
            }
            for(int i=ll;i<=llr;i++) {
                cout << cnt[i].y << " ";
            }
            cout << endl;
        }
    }
}

d. Friends and the Restaurant

主要是要发现两个人情况永远比三个人好,其实很好证明。我用预算减去支出表示我的富有程度。如果是三个人++-的富有,那么我两个++富有程度的一定优于三个,同理--+的少去一个-也更优。所以最优就是两两一组找最优。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int A[N],B[N],cnt[N];
int main()
{
    int t;
    cin >> t;
    while(t--) {
        int n;
        cin >> n;
        for(int i=1;i<=n;i++) {
            cin >> A[i];
        }
        for(int i=1;i<=n;i++) {
            cin >> B[i];
            cnt[i]=B[i]-A[i];
        }
        sort(cnt+1,cnt+1+n);
        int l=1,r=n,sum=0;
        while(l<r) {
            if(cnt[l]+cnt[r]>=0) {
                l++;
                r--;
                sum++;
            }else {
                l++;
            }
        }
        cout << sum << endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值