3.30日洛谷

1.删数问题
解题思路:
这样进行贪心:如果存在逆序的关系str[i] > str[j],那么就把str[i]删掉,然后从头开始遍历字符串,这里一定会有逆序的关系,因为超出str的范围之后是最小的,也就是最后一个字符一定大于之后的字符。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 260;
string str;
int k;
int main()
{
    cin >> str;
    cin >> k;
    int sum = 0,i = 0;
    while(true)
    {
        if(str[i] > str[i+1])
        {
            str.erase(i,1);
            while(str[0]=='0') str.erase(0,1);
            sum++;
            i = 0;
            if(sum == k) break;
        }
        else i++;
    }
    if(str.empty()) cout<<0<<endl;
    else cout<<str<<endl;
    return 0;
}

2.最大子段和
三种解题思路:
(1)贪心:站在ai的角度来看,如果前面维护的序列和已经是一个负数,那么我加入它们之后对我来讲是变差了,于是我决定另起炉灶。每次计算更新一次最大值,然后输出即可。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
int n;
int a[N];
int main()
{
    cin>>n;
    int sum = 0,ans = -0x3f3f3f3f;
    for(int i=0;i<n;i++)
    {
        int x;
        cin>>x;
        sum+=x;
        ans = max(sum,ans);
        if(sum<0) sum = 0;
        
    }
    cout<<ans<<endl;
    return 0;
    
}

(2) 动态规划的思想:状态表示为以i结尾的子段最大值,状态转移方程如下:f[i] = max(f[i]+a[i],a[i]),在转移的过程中更新最大值即可

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
int n;
int f[N];
int main()
{
    cin>>n;
    int ans = -0x3f3f3f3f;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        f[i] = max(f[i-1]+x,x);
        ans = max(ans,f[i]);
    }
    cout<<ans<<endl;
    return 0;
    
}

(3) 分治的思想:对于任意一个区间[l,r],其中点为mid,假设最大子段为[i,j],那么i,j的情况有以下三种:

  1. l<=i<=mid<j<=r;
  2. l<=i<=j<=mid
  3. mid+1<=i<=j<=r;
    第一种情况最好求,后两种情况可以递归推出来。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
int n;
int a[N];
int fun(int l,int r)
{
    // 计算[l,r]上[i,j]的和的最大值
    if(l == r)
    {
        return a[l];
    }
    int s1 = 0,s2 = 0;
    int ans1 = -0x3f3f3f3f,ans2 = -0x3f3f3f3f;
    int mid = l+r >> 1;
    for(int i=mid;i>=l;i--) //这里表示以mid结尾
    {
        s1+=a[i];
        ans1 = max(s1,ans1);
    }
    for(int i=mid+1;i<=r;i++) //这里表示以mid+1开始
    {
        s2+=a[i];
        ans2 = max(ans2,s2);
    }
    return max(ans1+ans2,max(fun(l,mid),fun(mid+1,r)));
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int ans = fun(1,n);
    cout<<ans<<endl;
    return 0;
    
}

3. 杂物
解题思路:可以根据关系构建出一张有向图,然后利用拓扑排序,求出每个点能处理完的最早时间,pre[j] = max(pre[j],pre[t] + w[j]),最后遍历求出最大的pre[i]。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e4+10,M = 1e6+10;
int n;
int h[N],e[M],ne[M],idx;
int w[N],indr[N],pre[N],st[N];
void add(int a,int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}
int main()
{
    memset(h, -1, sizeof h);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int id;
        cin>>id>>w[i];
        int x;
        cin>>x;
        while(x!=0)
        {
            add(x,id);
            indr[id]++;
            cin>>x;
        }
    }
    queue<int> q;
    for(int i=1;i<=n;i++)
    {
        if(indr[i] == 0)
        {
            q.push(i);
            pre[i] = w[i];
            
        }
    }
    while(!q.empty())
    {
        int t = q.front();
        q.pop();
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j = e[i];
            pre[j] = max(pre[j],pre[t]+w[j]);
            indr[j]--;
            if(indr[j] == 0) q.push(j);
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i ++ ) ans = max(ans,pre[i]);
    cout<<ans<<endl;
    return 0;
}

4. 轰炸
解题思路:枚举每一个点,把它当成中心点,考虑过这个点的直线最大的点的数量,取最大值。可以map<double,int>来存储相同斜率的情况,如果这个斜率之前没有出现过,则mp[key] = 2,否则就mp[key]+=1。
这个题有点类似与acwing周赛的这个题
4309 消灭老鼠

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
typedef pair<int, int> PII;
const int N = 710,inf = 0x3f3f3f3f;
PII a[N];
int n;
int main()
{
    cin>>n;
    for (int i = 0; i < n; i ++ )
    {
        int x,y;
        cin >> x >> y;
        a[i] = {x,y};
    }
    int ans = 1;
    for (int i = 0; i < n; i ++ )
    {
        unordered_map<double,int> mp;
        for (int j = 0; j < n; j ++ )
        {
            if( i == j ) continue;
            double key;
            if(a[i].first == a[j].first)
            {
                key = inf;
            }
            else
            {
                key = (double)(a[j].second- a[i].second)/(a[j].first - a[i].first);
            }
            if(!mp[key]) mp[key] = 2;
            else mp[key]+=1;
            ans = max(ans,mp[key]);
        }
    }
    cout<<ans<<endl;
    return 0;
}

贪心真难啊…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值