7.16训练

A - A CodeForces - 1257E

这个是原题,主要部分就是求最长上升序列的方法,用二分法能够AC!

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <algorithm>
#include <iomanip>
#include <map>
#include <queue>
#include <vector>
#include <set>
typedef long long ll;
using namespace std;
const int N = 2e5 + 5;
int s[N];
int main()
{
	int k1, k2, k3; cin >> k1 >> k2 >> k3;
	int n = k1 + k2 + k3;
	for (int i = 1; i <= n; i++)
	{
		cin >> s[i];
	}
	sort(s + 1, s + 1 + k1); sort(s + 1 + k1, s + 1 + k2 + k1);
	sort(s + k2 + 1 + k1, s + 1 + n);
	int maxx = 1;
	int f[N];
	int top =1;
	f[1]=-1;
	for (int i = 1; i <=n; i++)
	{
		int t = s[i];
		if (t > f[top])
			f[++top] = t;
		else
		{
			int l =1, r = top;
			int mid;
			while (l <= r)
			{
				mid = (l + r) / 2;
				if (t > f[mid])
				{
					l = mid + 1;
				}
				else
					r = mid - 1;
			}
			f[l] = t;
		}
	}
	cout << n-top+1<< endl;
}

CodeForces - 1256E

这个题是第二次做了,第一次自己没认真,这次一定要掌握!
题意:至少三个人一组,然后你要想办法让所有的组内的最大值最小值相差 的 所有的和最小,然后要输出他们的组的编号!
思路:最小3个人一组,其实最多也就5个人一组,再多的话就能分成两组了,这样 差就更小了,所以至多五个人,这个题用dp来做,设一个数组 dp[i] 表示前i个人所得到的最小 ‘差和’,然后在每一个i时,去枚举以i为开头的组的规模(3–5),用dp来记录min,同时把i存到L数组中,这个是为了后面表组号!
后面组号就是 开头那个人是 L[h],那么结尾那个人是h。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <algorithm>
#include <iomanip>
#include <map>
#include <queue>
#include <vector>
#include <set>
typedef long long ll;
using namespace std;
const int N = 2e5 + 5;
const int maxm = 2e5 + 5;
const int inf = 1e9;
struct Node
{
    int v, id;
}a[maxm];
int d[maxm];//d[i]表示分配前i个人需要的最小花费
int L[maxm];
int ans[maxm];
int n;
int cmp(Node a, Node b)
{
    return a.v < b.v;
}
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin>>a[i].v;
        a[i].id = i;
    }
    sort(a + 1, a + 1 + n, cmp);
    for (int i = 1; i <= n; i++) //初始化inf
        d[i] = inf;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 3;j <= 5; j++)//枚举队伍的长度(此时i为开头)
        {
            int t = d[i-1] + a[i+j-1].v - a[i].v;//花费为前i-1个人的花费d[i-1]加上a[i+j-1].v-a[i].v
            if (t< d[i + j - 1]) {
                d[i + j - 1] = t;
                L[i+j-1] = i;//记录区间左端点(右端点为i+j-1)
            }
        }
    }
    int now = n;
    int cnt = 0;
    while (now) 
    {//标记队伍编号
        cnt++;
        for (int i = L[now]; i <= now; i++) {
            ans[a[i].id] = cnt;
        }
        now = L[now] - 1;
    }
  cout << d[n] << " " << cnt << endl;
    for (int i = 1; i <= n; i++)
    {
        cout << ans[i] << " ";
    }
    cout << endl;
    return 0;
}

CodeForces - 1260E

题意:输入数字N,1-N分别代表着n个拳击手的战斗力,然后每个拳击手都可以被贿赂,每个人都有贿赂的金额,为了得到第一,你要付出多少金额,每次都是两两对决,获胜者进入下一轮。
思路:每次都是两两对决,假设你的位置是sign,i<sign的不贿赂了,你一定赢,所以你要管的是i>sign的部分,每次比赛完还剩多少人?,其实就是每次都÷2,,用一个优先队列储存[k,2*k)贿赂钱,每次都贿赂top()就可以。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <algorithm>
#include <iomanip>
#include <map>
#include <queue>
#include <vector>
#include <set>
typedef long long ll;
using namespace std;
const int N =1000000;
ll a[N],b[N];
int main()
{
	priority_queue<ll, vector<ll>, greater<ll> > q;
	ll n; cin >> n; ll s = 0;
	ll sign; int c = 1;
	for (ll i = 1; i <= n; i++)
	{
		cin >> a[i];
		if (a[i] == -1)
			sign = i;
	}
	ll k = n;
	while (k > sign)
	{
		for (ll i = k; i <= n && i < 2 * k; i++)
			q.push(a[i]);
		s += q.top();
		q.pop();
		k = k / 2;

	}
	cout << s << endl;


}

D - D CodeForces - 1272E

题意:一个长度为 n 的序列,每个位置可以跳到 i−ai 或者 i+ai求出每个位置最少需要跳几次,可以使起始位置和结束位置的奇偶性不同。
思路:建立一个vector容器 ,将某个数能到达的位置 为下标 将i存入,然后对每个i进行一次遍历,根据i点的奇偶性,若为奇数值,那么它上一个点到奇数值点的最短距离只有1一种可能。i的x值更新为1,而y记录的是i点到下一个y点的距离,然后依次类推。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <algorithm>
#include <iomanip>
#include <map>
#include <queue>
#include <vector>
#include <set>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int N = 2e5 + 5;
const int maxm = 2e5 + 5;
const int maxn = 200005;
using namespace std;
struct node
{
	int val, x, y;
}a[maxn];
vector<int> v[maxn];
int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		a[i].x = a[i].y = inf;
		cin >> a[i].val;
		if (i + a[i].val <= n)
			v[i + a[i].val].push_back(i);
		if (i - a[i].val>=1)
			v[i - a[i].val].push_back(i);
	}
	queue<int>q;
	for (int i = 1; i <= n; i++)
	{
		q.push(i);
	}
	while (!q.empty())
	{
		int head = q.front();
		q.pop();
		for (int i : v[head])//v[head]中放的是下一次移动能到达head位置的点的编号,即上一个点的编号
		{
			if (a[head].val%2==1)//如果head点值为奇数
			{
				if (a[i].x>1|| a[i].y > a[head].y + 1)//head点为奇数值,那么它上一个点到奇数值点的最短距离只有1一种可能。i的x值更新为1,而y记录的是head点到下一个y点的距离
				{
					a[i].x = 1;
					if (a[i].y > a[head].y + 1)//位置i的点用对应的y继承位置head点到值为偶数的点的最短距离
						a[i].y = a[head].y + 1;
					q.push(i);
				}
			}
			else
			{
				if (a[i].y > 1 || a[i].x > a[head].x + 1)
				{
					a[i].y = 1;
					if (a[i].x > a[head].x + 1)
						a[i].x = a[head].x + 1;
					q.push(i);
				}
			}
		}
	}
	for (int i = 1; i <= n; i++)
	{
		if (a[i].val%2==1)
		{
			cout << (a[i].y == inf ? -1 : a[i].y) << " ";
		}
		else
			cout << (a[i].x == inf ? -1 : a[i].x) << " ";
	}
}

E挺简单的 不说了

FCodeForces - 1251D

第二次!
题意: 给n个人发工资,总钱数为s。每个人有一个工资范围。要求一个发工资方案,使得工资中位数最大,求这个中位数。
思路:假设当前中位数为x,我们只需要保证有n/2+1个位置包含x就可以了。按照左端点由小到大排序(pair 先按first 其次按second),然后倒序去找,这样我们可以优先考虑>=x的数,同时需要判断最小价值是否大于s以及是否有n/2+1个数>=x.

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <algorithm>
#include <iomanip>
#include <map>
#include <queue>
#include <vector>
#include <set>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int MAXN = 200005;
const int INF = 1e9;
vector<pair<ll, ll>> v;
ll n, s, x, y;
bool gg(ll x)
{
    ll t = s, cnt = n / 2 + 1;
    for (int i = n - 1; i >= 0; i--)
    {
        if (v[i].second >= x && cnt > 0)
        {
            cnt--;
            t -= max(x, v[i].first);
        }
        else
        {
            t -= v[i].first;
        }
    }
    return (!cnt) && t >= 0;
}

int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        v.clear();
        cin >> n >> s;
        for (int i = 0; i < n; i++)
        {
            cin >> x >> y;
            v.push_back(make_pair(x, y));
        }
        sort(v.begin(), v.end());
        ll l = 0, r = INF;
        while (l <= r)
        {
            int mid = (l + r) >> 1;//  ==/2!;
            if (gg(mid)) l = mid + 1;
            else r = mid - 1;
        }
        cout << l - 1 << endl;
    }
}

反思:这个还是出现了原题自己没AC ,那些都是之前感觉太难了,就没认真看的题目,自己总是知难而退,我以后会认真处理题目,写过的题解也不能光当做作业,我也要学习群里同学 的做法,常常回看,重做题目,来提高自己的思想水平!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值