SDUT 2023 Summer Individual Contest - 5(for 22)Gym - 101911

A - Coffee Breakt

题意:给你n,m,d三个数分别代表n个休息时刻,休息时间不会大于m,最小时间间隔,让你将这n个数分配到最少的天数里面,使的他们在同一天内的时间间隔满足大于d

思路:我们用优先对列来保持它的单调性,用map来记录他们分到那一天,开一个新的数组来保留其原来的顺序

我们从小到大枚举其休息时间的顺序,如果当前休息时间   a[i],和堆顶最小休息时刻a[k],使得a[i]-a[k]= d,我们就通过map将天数传递给a[i],然后弹出堆顶,让其跟新最小值即可

#include 
using namespace std;
#define pi 3.1415926
#define X first
#define Y second
#define endl "\n"
// #define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 2e5 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
int n, m, d;
priority_queue, greater> q;
int a[N], b[N];
map mp;
void solve()
{
	cin >> n >> m >> d;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		b[i] = a[i];
	}
	sort(a + 1, a + 1 + n);
	mp[a[1]] = 1;
	q.push(a[1]);
	int ans = 1;
	for (int i = 2; i <= n; i++)
	{
		int t = q.top();
		if (a[i] - t > d)
		{
			mp[a[i]] = mp[t];
			q.pop();
		}
		else
		{
			ans++;
			mp[a[i]] = ans;
		}
		q.push(a[i]);
	}
	cout << ans << endl;
	for (int i = 1; i <= n; i++)
		cout << mp[b[i]] << ' ';
}

int main()
{
	Ysanqian;
	int T;
	T = 1;
	// cin >> T;
	while (T--)solve();
	return 0;
}

B - Glidert​​​​​​​t

题意:有n个气流带的左右端点和一个初始飞机高度,在气流带里由于气流原因你不会下降,而在非气流带则会下降 ,起点的x值可以任你选择,最后降落下来到地面的点,离你选择起点的最远距离是多少

思路:我们知道在非气流带向前走一步则会下降一步,故非气流带我们最多可以走小于h,

而且我们贪心的想我们一定是重那个气流带的左端点开始跳机,这样才会最优

先说一个简单双指针的做法,就是先固定起点然后向后找终点,当大于h时我们在向右移动左端点

#include 
using namespace std;
#define pi 3.1415926
#define X first
#define Y second
#define endl "\n"
// #define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 2e5 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
struct node
{
	int l, r;
} a[N];
int n, h;
int maxx;
void solve()
{
	cin >> n >> h;
	for (int i = 1; i <= n; i++)
		cin >> a[i].l >> a[i].r;
	int l = 1, r = 1;
	int hh = 0;	 // 非气流长度
	int len = 0; // 气流长度
	for (int r = 1; r <= n; r++)
	{
		if (r > 1)
		{
			hh += a[r].l - a[r - 1].r;
			while (hh >= h)
			{
				hh -= a[l + 1].l - a[l].r;
				len -= a[l].r - a[l].l;
				l++;
			}
		}
		len += a[r].r - a[r].l;
		maxx = max(maxx, len);
	}
	cout << h + maxx << endl;
}

int main()
{
	Ysanqian;
	int T;
	T = 1;
	// cin >> T;
	while (T--)solve();
	return 0;
}

 后一种做法就是前缀和加二分

就是枚举起点,然后找终点然后取最大值即可

#include 
using namespace std;
#define pi 3.1415926
#define X first
#define Y second
#define endl "\n"
// #define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 2e5 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
struct node
{
	int l, r;
} pos[N];
int n, h, maxx;
int a[N], b[N]; // a[i]表示前i个气流带的总长度,b[i]表示前i个气流带前无气流带的总长度。
void solve()
{
	cin >> n >> h;
	for (int i = 1; i <= n; i++)
		cin >> pos[i].l >> pos[i].r;
	a[1] = pos[1].r - pos[1].l;
	b[1] = 0;
	for (int i = 2; i <= n; i++)
	{
		a[i] = a[i - 1] + pos[i].r - pos[i].l;
		b[i] = b[i - 1] + pos[i].l - pos[i - 1].r;
	}
	b[n + 1] = inf;//lower_bound如果找不到大于等于的就会返回最后一个下标的下一个位置
	for (int i = 1; i <= n; i++)
	{
		int idx = lower_bound(b + 1, b + 1 + n, b[i] + h) - b ;//减返回的是其在b数组中以1开始的下标
		//cout<> T;
	while (T--)
		solve();
	return 0;
}

C - Bacteria

题意:n个元素,权值相同的元素可以直接合并,如果权值不同可以去商店里购买任意大小权值的元素,再去合并,我们希望在购买次数较少的情况下,使最后的集合合并为一个元素,如果无论多少次都无法完成最终合并就输出-1,否则输出购买次数。

思路:维护小根堆。为什么要想到先处理最小的元素呢。比如3,6,我们希望购买次数少,那么显然就买一个3 即可!如果堆顶a,b相等则pop(a,b),push(a+b),如过不相等则判断a不断乘以2是否可以化为b

#include 
using namespace std;
#define pi 3.1415926
#define X first
#define Y second
#define endl "\n"
#define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
int n, a[N], ans;
priority_queue, greater> q;
bool flag;
void solve()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		int x;
		cin >> x;
		q.push(x);
	}
	while (q.size() > 1)
	{
		int a = q.top();
		q.pop();
		int b = q.top();
		if (a == b)
		{
			q.pop();
			q.push(a + b);
		}
		else
		{
			if (b % a != 0 || b / a % 2 != 0)
			{
				flag = 1;
				break;
			}
			for (int i = a; i <= b; i *= 2)
			{
				if (i == b)
				{
					q.pop();
					q.push(2 * b);
					break;
				}
				ans++;
			}
		}
	}
	if (flag)
		cout << -1 << endl;
	else
		cout << ans << endl;
}
signed main()
{
	Ysanqian;
	int T;
	T = 1;
	// cin >> T;
	while (T--)
		solve();
	return 0;
}

D - Masquerade strikes back

题意:给你n个数,让用不同的因子a*b表示这个数,例如6=2*3,6=3*2,这两个认为不同

思路:我们先统计个数,再分解因子判断即可,具体看代码注释即可

#include 
using namespace std;
#define pi 3.1415926
#define X first
#define Y second
#define endl "\n"
//#define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e7 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
int n,a[N],cnt[N],idx[N];
vectorg[N];
int main()
{
	Ysanqian;
	scanf("%d",&n);
   for(int i=1;i<=n;i++)
   {
   scanf("%d",&a[i]);
   cnt[a[i]]++;//cnt来统计次数
   }
   for(int i=1;i<=n;i++){
     int x=a[i];
    if(g[x].size())continue;
    for(int j=1;j<=x/j;j++)
    {
        if(x%j==0)
        {
            g[x].pb(j);//一对存入,便于输出
            g[x].pb(x/j);
            if(x/j!=j)//翻转顺序存入,例如3,2和2,3
            {
            g[x].pb(x/j);
            g[x].pb(j);
            }
        }
        if(g[x].size()>=2*cnt[x])//这里一定要有,如果够了就不要再分解了,不然会超时
        break;
    }
    if(g[x].size()<2*cnt[x])
    {
        puts("NO");
        return 0;
    }
    }
    puts("YES");
   for(int i=1;i<=n;i++){
     int x=a[i];
	 int y=idx[x];
	 printf("%d %d\n",g[x][y],g[x][y+1]);
	 idx[x]+=2;//idx为a[i]的因子用了多少个
   }
	return 0;
}

F - Tickets

题意:这题也没什么要说的

思路:就是要注意看请数据复杂度,我们就可以想到预处理一下,

这道题不说完全是个DP题,也至少用到了滚动数组的思路。

我们从小到大枚举,边枚举边更新答案,因为每个数都和某个幸运值一一对应,我们可以存下当前这个数的幸运值,然后从小到大枚举所有的幸运值,这里所有的幸运值并不是所有,因为从小到大枚举,所有当前的幸运值都来自于比当前的数小的数——滚动思想。所以把这些数字求和就是这个数字的答案,再开个数组记下来。

#include 
using namespace std;
#define pi 3.1415926
#define X first
#define Y second
#define endl "\n"
//#define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
int n;
int ans[N];
int cnt[29];
void init()
{
 for(int i=0;i<=N;i++)
 {
	int x=i;
	int a,b,c,d,e,f;
	a=x%10,x/=10;
	b=x%10,x/=10;
	c=x%10,x/=10;
	d=x%10,x/=10;
	e=x%10,x/=10;
	f=x%10,x/=10;
    int t=abs(a+b+c-d-e-f);
	cnt[t]++;
	for(int j=0;j>x;
	int luck=ans[x];
	cout<> T;
	while (T--)solve();
	return 0;
}


 

你可能感兴趣的:(训练赛,c++)