题意:给你n,m,d三个数分别代表n个休息时刻,休息时间不会大于m,最小时间间隔,让你将这n个数分配到最少的天数里面,使的他们在同一天内的时间间隔满足大于d
思路:我们用优先对列来保持它的单调性,用map来记录他们分到那一天,开一个新的数组来保留其原来的顺序
我们从小到大枚举其休息时间的顺序,如果当前休息时间 a[i],和堆顶最小休息时刻a[k],使得a[i]-a[k]
#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;
}
题意:有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;
}
题意: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;
}
题意:给你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;
}
题意:这题也没什么要说的
思路:就是要注意看请数据复杂度,我们就可以想到预处理一下,
这道题不说完全是个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;
}