2019 牛客 多校赛 第七场

slove  4/11

rank  328

补题   7/11

--------------------------------------------------------

link

A、String

贪心暴力跑最长符合条件的,签到

#include <bits/stdc++.h>
using namespace std;
char s[205];
int str[205];
string ans[205];
int num1[205], num0[205], num[205];
int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%s", s);
		memset(str, 0, sizeof(str));
		memset(num, 0, sizeof(num));
		memset(num1, 0, sizeof(num1));
		memset(num0, 0, sizeof(num0));
		int tot = 0;
		int len = strlen(s);
		/*第一次预处理*/
		for (int i = 0; i < len;)
		{
			if (s[i] == '1')
			{
				str[++tot] = 1;
				while (s[i] == '1' && i < len)
				{
					num[tot]++;
					i++;
				}
			}
			else
			{
				str[++tot] = 0;
				while (s[i] == '0' && i < len)
				{
					num[tot]++;
					i++;
				}
			}
		}
		/*第二次*/
		int start = -1, idx;
		int Len = -1;
		for (int i = 1; i <= tot;)
		{

			if (start == -1)
			{
				start = str[i];
				idx = i;
			}
			if (start == 1)
			{
				++Len;
				ans[Len] = "";
				for (int j = 1; j <= num[idx]; j++)
					ans[Len] += '1';
				num1[Len] = num[idx];
				i++;
				start = -1;
			}
			else
			{
				++Len;
				ans[Len] = "";
				for (int j = 1; j <= num[idx]; j++)
					ans[Len] += '0';
				num0[Len] = num[idx];
				++i;
				for (int j = 1; j <= num[i]; j++)
					ans[Len] += '1';
				num1[Len] = num[i];
				++i;
				start = -1;
			}
		}

		vector<string>v;
		for (int i = 0; i <= Len;)
		{
			string t = ans[i];
			int f = i;
			int j = i + 1;
			bool ff = true;
			for (; j <= Len; j++)
			{
				if (num1[j] == 0)
				{
					break;
				}
				else if (num0[f] > num0[j])
				{
					t += ans[j];
					ff = false;
				}
				else if (num0[f] == num0[j] && (num1[f] < num1[j] || (num1[f] == num1[j] && ff == true)))
				{
					t += ans[j];
					if (num1[f] != num1[j])
						ff = false;
				}
				else
					break;
			}
			i = j;
			v.push_back(t);
		}
		len = v.size();
		for (int i = 0; i < len; i++)
		{
			cout << v[i];
			printf("%c", i == len - 1 ? '\n' : ' ');
		}
	}
}

B、Irreducible Polynomial

判断一个多项式是否可以被分解

最高次方大于等于3的一定可以被分解,最高次方小于2的一定不能被分解。最高次方等于2的,有解就可以被分解,否则,不可以被分解。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a[100];
int n;
int main()
{
	int T;
	scanf("%d", &T);
	while (T--) 
	{
		scanf("%d", &n);
		for (int i = n; i >= 0; i--)
		{
			scanf("%lld", &a[i]);
		}
		if (n >= 3)
			printf("No\n");
		else if (n == 2)
		{
			ll deta = a[1] * a[1] - 4 * a[0] * a[2];
			if (deta >= 0)
				printf("No\n");
			else
				printf("Yes\n");
		}
		else if (n == 1 || n == 0)
		{
			printf("Yes\n");
		}
	}
	return 0;
}

C、Governing sand

有很多种树,他们的高度,移除所花费的代价,数量已知,现在希望让最高的树的数量严格大于其他树的数量,问移除树需要花费的最小代价。

权值线段树求区间前K小,赛事更新操作没写 + 号,数量没用 ll ,难受啊,本来5题了

1、首先考虑将高度离散化,并且统计小于等于某高度的树的数量,和移除这些树的总代价

2、考虑枚举每一种高度作为最高高度,我们可以 O(1) 算出删除所有比他高的数目的总代价,并且可以知道需要留多少颗高度小于他的树

3、于是题目就变成了,求区间前K小,

4、注意需要保证在所有同一高度的数木全部加入到区间中才更新答案,否则,若最高高度的树删除的代价最小,可以会删最高高度的树,但显然这是不合法的。

5、题目给的代价的范围是1-200,赛时没注意,所以也可以遍历找最小代码,但如果代价是1e9,那么就只能权值线段树维护区间前 K 小和了。

#include <bits/stdc++.h>
#define ll long long
#define lson left,mid,k<<1
#define rson mid+1,right,k<<1|1
#define imid int mid=(left+right)/2;
using namespace std;
const int MAXN = 2e5 + 5;
struct note
{
	ll h;
	ll val;
	ll num;
}in[MAXN];
ll t[MAXN];
ll num[MAXN];
ll money[MAXN];
struct node
{
	int l;
	int r;
	ll cnt;
	ll sum;
	ll val;
}que[MAXN * 4];
int ql, qr;
ll val;
void up(int k)
{
	que[k].sum = que[k << 1].sum + que[k << 1 | 1].sum;
	que[k].cnt = que[k << 1].cnt + que[k << 1 | 1].cnt;
}
void build(int left, int right, int k)
{
	que[k].l = left;
	que[k].r = right;
	if (left == right)
	{
		que[k].cnt = 0;
		que[k].val = 0;
		que[k].sum = 0;
		return;
	}
	imid;
	build(lson);
	build(rson);
	up(k);
}
void update(int left, int right, int k)
{
	if (qr < left || right < ql)
		return;
	if (ql <= left && right <= qr)
	{
		que[k].cnt += in[val].num;
		que[k].val = t[in[val].val];
		que[k].sum = que[k].cnt * que[k].val;
		return;
	}
	imid;
	update(lson);
	update(rson);
	up(k);
}
ll query(int left, int right, int k, ll val)
{
	if (left == right)
	{
		return min((ll)val, que[k].cnt) * que[k].val;
	}
	imid;
	if (val <= que[k << 1].cnt)
	{
		return query(lson, val);
	}
	else if (val > que[k << 1].cnt)
	{
		val -= que[k << 1].cnt;
		return que[k << 1].sum + query(rson, val);
	}
}
int main()
{
	int n;
	while (scanf("%d", &n) > 0)
	{
		for (int i = 1; i <= n; i++)
		{
			num[i] = 0;
			money[i] = 0;
			scanf("%lld%lld%lld", &in[i].h, &in[i].val, &in[i].num);
			t[i] = in[i].h;
		}
		sort(t + 1, t + 1 + n);
		int qq = unique(t + 1, t + 1 + n) - t - 1;
		for (int i = 1; i <= n; i++)
			in[i].h = lower_bound(t + 1, t + 1 + qq, in[i].h) - t;
		sort(in + 1, in + 1 + n, [](note q, note w) {
			if (q.h == w.h)
				return q.val < w.val;
			return q.h < w.h;
			});
		for (int i = 1; i <= n; i++)
		{
			num[in[i].h] += in[i].num;
			money[in[i].h] += in[i].num * in[i].val;
			t[i] = in[i].val;
		}
		for (int i = 1; i <= n; i++)
		{
			money[i] += money[i - 1];
			num[i] += num[i - 1];
		}
		sort(t + 1, t + 1 + n);
		qq = unique(t + 1, t + 1 + n) - t - 1;
		for (int i = 1; i <= n; i++)
			in[i].val = lower_bound(t + 1, t + 1 + qq, in[i].val) - t;
		build(1, 200000, 1);
		ll ans = 2e18;
		for (int i = 1; i <= n; i++)
		{
			ll res = money[in[n].h] - money[in[i].h];
			ll shengyu = num[in[i].h - 1];
			ll cnt = max(shengyu - (num[in[i].h] - num[in[i].h - 1] - 1), 0LL);//取的个数
			if (in[i].h != in[i - 1].h)
			{
				val = cnt;
				res += query(1, 200000, 1, val);
				ans = min(ans, res);
			}
			ql = qr = in[i].val;
			val = i;
			update(1, 200000, 1);
		}
		printf("%lld\n", ans);
	}
}

D、Number

签到

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 50005;
char s[100005];
int get(int n)
{
	int cnt = 0;
	while (n)
	{
		n /= 10;
		cnt++;
	}
	return cnt;
}
int main()
{
	{
		int n, m;
		scanf("%d%d", &n, &m);
		int cnt = get(m);
		if (n >= cnt)
		{
			printf("%d", m);
			for (int i = 0; i < n - cnt; i++)
				printf("0");
			printf("\n");
		}
		else
		{
			printf("T_T\n");
		}
	}
}

E、find the median

权值线段树维护区间个数,然后加上诡异的离散化。

https://blog.csdn.net/qq_41608020/article/details/99187576

H、Pair

题意:给出三个数字A B C 在1-A中任取一个数字x 在1-B中任取一个数字y 求至少满足 x&y > c 或者 x^y < c其中一个的(x,y)的对数
做法: 数位DP

#include<bits/stdc++.h>
using namespace std;
#define ll long long
/*  pos x - limit1 y - limit x&y - limit  x^y - limit  x - 0 y - 0*/
ll  dp[31][2][2][2][2][2][2][2][2];
int a[31], b[31], c[31];
/* limitc1表示 x&y是否等于c  ismax1表示x&y是否小于c  limitc2 表示 x^y是否等于 c ismax2表示x^y是否大于c*/
ll dfs(int pos, int limitx, int limity, int limitc1, int ismax1, int limitc2, int ismax2, int zero1, int zero2)
{
	if (pos == -1)
	{
		if ((limitc1 == 0 && ismax1 == 0) || (limitc2 == 0 && ismax2 == 0) && zero1 == 0 && zero2 == 0)
			return 1ll;
		return 0;
	}
	if (dp[pos][limitx][limity][limitc1][ismax1][limitc2][ismax2][zero1][zero2] != -1)
		return dp[pos][limitx][limity][limitc1][ismax1][limitc2][ismax2][zero1][zero2];
	ll ans = 0;
	int mx = limitx ? a[pos] : 1;
	int my = limity ? b[pos] : 1;
	for (int i = 0; i <= mx; i++)
	{
		for (int j = 0; j <= my; j++)
		{
			int t1 = ismax1, t2 = ismax2;
			if (limitc1 == 1 && (i & j) < c[pos])
				t1 = 1;
			if (limitc2 == 1 && (i ^ j) > c[pos])
				t2 = 1;
			ans += dfs(pos - 1, limitx && i == mx, limity && j == my, limitc1 && (i & j) == c[pos], t1, limitc2 && (i ^ j) == c[pos], t2, zero1 && i == 0, zero2 && j == 0);
		}
	}
	return dp[pos][limitx][limity][limitc1][ismax1][limitc2][ismax2][zero1][zero2] = ans;
}
int main()
{
	int T;
	scanf("%d", &T);

	while (T--)
	{
		memset(dp, -1, sizeof(dp));
		int A, B, C;
		scanf("%d %d %d", &A, &B, &C);
		for (int i = 0; i <= 30; i++)
		{
			if (A & (1 << i))
				a[i] = 1;
			else
				a[i] = 0;
			if (B & (1 << i))
				b[i] = 1;
			else
				b[i] = 0;
			if (C & (1 << i))
				c[i] = 1;
			else
				c[i] = 0;
		}
		ll t3 = dfs(30, 1, 1, 1, 0, 1, 0, 1, 1);
		printf("%lld\n", t3);
	}
}

J、A+B problem

签到

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 50005;
int main()
{
	int T;
	sc("%d", &T);
	while (T--)
	{
		ll a, b;
		scanf("%lld%lld", &a, &b);
		ll q = 0, w = 0;
		while (a)
		{
			q = q * 10 + a % 10;
			a /= 10;
		}
		while (b)
		{
			w = w * 10 + b % 10;
			b /= 10;
		}
		ll ans = q + w;
		ll ans2 = 0;
		while (ans)
		{
			ans2 = ans2 * 10 + ans % 10;
			ans /= 10;
		}
		printf("%lld\n", ans2);
	}
}

 

全部评论

相关推荐

11-05 07:29
贵州大学 Java
点赞 评论 收藏
分享
10-24 11:10
山西大学 Java
若梦难了:哥们,面试挂是很正常的。我大中厂终面挂,加起来快10次了,继续努力吧。
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务