2022.07.08 暑假集训 个人排位赛(三)

本文通过分析三道编程竞赛题目,探讨了动态规划、区间查找和问题解决策略。在ProblemA中,利用ST表和二分查找解决区间最大值与最小值相等的问题;ProblemB展示了动态规划的应用,构建值的组合;ProblemF讨论了根据汽车速度和修理时间制定最佳行驶策略。这些案例揭示了在编程竞赛中如何高效地运用算法解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2022.07.08 暑假集训 个人排位赛(三)

赛后反省

动态规划的敏感度不够,还是一直在错的方法死磕。然后另外一道题对于一些特征不太敏感,已经接近正解了,就差一步。

继续加油。

Problem A

出处

Codeforces-689D

题解

ST表+二分

利用ST表之后,枚举区间的左坐标。当右区间不断扩大的时候,最大值是一个递增序列,最小值是一个递减序列。所以用两次二分,来找到在两段序列中最大值和最小值相等的区间是否存在。

代码


// Good Good Study, Day Day AC.
#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <cstring>
#include <math.h>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#define ffor(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define rrep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define ll long long
#define INF 0x7f7f7f7f7f7f7f7f
#define inf 0x7f7f7f7f
#define PII pair<int,int>
#define int long long

using namespace std;

const int N = 1e6 + 6;
int n, T = 1;
int a[N][22];
int b[N][22];

int get_max(int x, int y) {
    int mid = log2(y - x + 1);
    return max(a[x][mid], a[y - (1 << mid) + 1][mid]);
}

int get_min(int x, int y) {
    int mid = log2(y - x + 1);
    return min(b[x][mid], b[y - (1 << mid) + 1][mid]);
}

bool check_L(int x, int y) {
    int minn = get_min(x, y);
    int maxn = get_max(x, y);
    if (maxn >= minn) return true;
    else return false;
}

bool check_R(int x, int y) {
    int minn = get_min(x, y);
    int maxn = get_max(x, y);
    if (maxn > minn) return true;
    else return false;
}


void ready()
{
    cin >> n;
    ffor(i, 1, n) {
        cin >> a[i][0];
    }
    ffor(j, 1, 18) {
        ffor(i, 1, n) {
            a[i][j] = max(a[i][j - 1], a[i + (1 << (j - 1))][j - 1]);
        }
    }
    //mst(b,INF);
    ffor(i, 1, n) {
        cin >> b[i][0];
    }
    ffor(j, 1, 18) {
        ffor(i, 1, n) {
            b[i][j] = min(b[i][j - 1], b[i + (1 << (j - 1))][j - 1]);
        }
    }
    int ans = 0;
    ffor(i, 1, n) {
        int L = 0, R = 0;
        int l = i, r = n, mid;
        while (l < r) {
            mid = l + r >> 1;
            if (check_L(i, mid)) {
                r = mid;
            }
            else {
                l = mid + 1;
            }
        }
        L = l;
        l = i; r = n;
        while (l < r) {
            mid = l + r + 1>> 1;
            if (check_R(i, mid)) {
                r = mid - 1;
            }
            else {
                l = mid;
            }
        }
        R = l;
       // cout << "i=" << i << ' ' << L << ' ' << R << '\n';
        if (get_max(i, L) == get_min(i, R)) {
            ans += R - L + 1;
        }
    }
    cout << ans;
}


void work()
{

}

signed main()
{
    IOS;
    ready();
    //	cin>>T;
    while (T--) {
        work();
    }
    return 0;
}





Problem B

出处

Codeforces-687C

题解

动态规划。

dp[i][j]dp[i][j]dp[i][j]代表值为i时是否能被j给构造。如果能则为1,否为0。

如果dp[i][j]=1dp[i][j]=1dp[i][j]=1,那么当加入一个新的值c时,dp[i+c][j]=1dp[i+c][j]=1dp[i+c][j]=1dp[i+c][j+c]=1dp[i+c][j+c]=1dp[i+c][j+c]=1都成立。那么转移方程也得到了。

代码


// Good Good Study, Day Day AC.
#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <cstring>
#include <math.h>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <map>
#include <algorithm> 
#include <unordered_map>
#include <unordered_set>
#define ffor(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define rrep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define ll long long
#define INF 0x7f7f7f7f7f7f7f7f
#define inf 0x7f7f7f7f
#define PII pair<int,int>
#define int long long

using namespace std;


const int N = 505;
bool dp[N][N];
int n, T = 1, k;

void ready()
{
	cin >> n >> k;
	dp[0][0] = true;
	ffor(t, 1, n) {
		int c;
		cin >> c;
		rrep(i, k, c) {
			ffor(j, 0, k-c) {
				if (dp[i - c][j])
					dp[i][j] = dp[i][j + c] = true;
			}
		}
	}
}


void work()
{
	int ans = 0;
	ffor(i, 0, k) ans += dp[k][i];
	cout << ans << '\n';
	ffor(i, 0, k) {
		if (dp[k][i])
			cout << i << ' ';
	}
}

signed main()
{
	IOS;
	//	cin>>T;
	while (T--) {
		ready();
		work();
	}
	return 0;
}





Problem F

出处

Codeforces-702D

题解

思维题。

距离比较小,直接开车就到达。

如果k距离时,走路快过汽车走并且修车,那么先开车走k公里,剩下的路全都走路。

如果k距离时,走路慢过汽车走并修车,那么后面每个k公里都开车,直到剩下比k公里小的路程没走时,考虑一下修车再走快还是直接走路快,进行选择即可。

代码


// Good Good Study, Day Day AC.
#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <cstring>
#include <math.h>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#define ffor(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define rrep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define ll long long
#define INF 0x7f7f7f7f7f7f7f7f
#define inf 0x7f7f7f7f
#define PII pair<int,int>
#define int long long

using namespace std;

int n, T = 1;
int d,k,a,b,t;


void ready()
{
    cin>>d>>k>>a>>b>>t;
    if(d<=k){
        cout<<d*a;
        return;
    }
    if(a*k+t>b*k){
        int ans=k*a;
        d-=k;
        ans+=d*b;
        cout<<ans;
        return;
    }
    else{
        int cnt=d/k;
        int ans=cnt*a*k + (cnt-1)*t;
        d=d%k;
        if(cnt==0) ans=0;
        if(a*d+t>=b*d)
            ans+=b*d;
        else{
            ans+=a*d;
            if(cnt) ans+=t;
        }
        cout<<ans;
    }
}


void work()
{

}

signed main()
{
	IOS;
    ready();
	//	cin>>T;
	while (T--) {
		work();
	}
	return 0;
}





Problem G

出处

Codeforces-1234A

题解

平均数,上进位。

代码


// Good Good Study, Day Day AC.
#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <cstring>
#include <math.h>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#define ffor(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define rrep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define ll long long
#define INF 0x7f7f7f7f7f7f7f7f
#define inf 0x7f7f7f7f
#define PII pair<int,int>
#define int long long

using namespace std;

int n, T = 1;


void ready()
{

}


void work()
{
    cin>>n;
    int sum=0;
    ffor(i,1,n){
        int x;
        cin>>x;
        sum+=x;
    }
    int ans=(sum+n-1)/n;
    cout<<ans<<'\n';
}

signed main()
{
	IOS;
    ready();
    cin>>T;
	while (T--) {
		work();
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值