961(div.2)A- Diagonals
由于对角线分布为1~n~1,所以先填中间可容纳最大的,然后填两边,一直填到顶角,并记录填的对角线次数。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
int n;
int k;
int num;
void slove(int n)
{
for (int i = n; i >= 1; i--)
{
if (k <= 0)
{
break;
}
if (i == n)
{
k -= i;
num++;
}
else {
k -= i;
num++;
if (k > 0)
{
k -= i;
num++;
}
}
}
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int t;
cin >> t;
while (t--)
{
cin >> n;
cin >> k;
num = 0;
slove(n);
cout << num << endl;
}
return 0;
}
961(div.2)B1 - Bouquet (Easy Version)
NO .1 小数替换大数
思路就是从小到大,先找“小数”,然后去找比小数大1的“大数”,然后把小数替换成大数,但是小数有数量,钱有限制,根据此条件去判断能替换几个大数,每把1个小数替换成1个大数,花瓣数量就加1。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n';
#define int long long
const int N = 2e5 + 10;
signed main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int t;
cin >> t;
while (t--)
{
int n, m;
cin >> n >> m;
map<int, int>a;
vector<pair<int, int>>arr;
for (int i = 1; i <= n; i++)
{
int x;
cin >> x;
a[x]++;
}
for (auto k : a) //利用Map排好序后存入vector,first为花瓣,second为数量
{
arr.push_back({ k.first,k.second });
}
ll ans = 0;
ll num = 0;
for (int i = 0; i < arr.size()-1; i++) //从小到大遍历花瓣种类
{
int x = m / arr[i].first; //能买几个小数
int y = m % arr[i].first; //买完小数花瓣后还剩下多少
if (arr[i+1].first-arr[i].first==1) //如果下一个正好是现在的"大数"(相差1)
{
if (arr[i].second >= x)//如果小数的数量足够
{
if (arr[i + 1].second >= min(x, y)) //下面要把小数换成大数,看看能换几个:min(x,y)去找小数个数和所余的最小值,即能换几个小数
{
ans = max(ans, arr[i].first * x + min(x, y)); //如果大数的数量够换,就把能换的小数换了
}
else {
ans = max(ans, arr[i].first * x + arr[i+1].second); //因为大数和小数就差1,所以替换后也就是加1即可,所以加大数的数量就行。
}
}
else if (arr[i].first * arr[i].second + arr[i + 1].first * arr[i + 1].second > m)//如果小数数量不够且把大数和小数都算上却大于m
{
int xx = (m - arr[i].first * arr[i].second) / arr[i + 1].first; //都选小数后看看还能买几个大数,补上
int yy = (m - arr[i].first * arr[i].second) % arr[i + 1].first;//补大数后看看还剩多少
if (arr[i + 1].second - xx >= min(yy, arr[i].second)) //补大数后看看剩下的大数的数量够不够换小数。如果够。能被换的小数的数量是min(...)
{
ans = max(ans, m - yy + min(yy, arr[i].second)); //m-yy是都选小数且用大数补后的花瓣数量,加上能被换的小数的数量才是最终的。道理与上一个一样。
}
else { //如果数量不够换,则加上剩下的大数数量。
ans = max(ans, m - yy + arr[i + 1].second - xx);
}
}
else { //如果大数和小数都能买上,则最终就是所有的花瓣数
ans = max(ans, arr[i].first * arr[i].second + arr[i + 1].first * arr[i + 1].second);
}
}
}
for (auto p : arr) //如果花瓣都相差1以上或者就是去看单买一种花的情况
{
if (p.first * p.second <= m)
{
ans = max(ans, p.first * p.second);
}
else {
ans = max(ans, p.first * (m/p.first));
}
}
cout << ans << endl;
}
return 0;
}
NO.2 滑动窗口,找最大区间和
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n';
const int N = 2e5 + 10;
#define int long long
signed main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int t;
cin >> t;
while (t--)
{
int n, m;
cin >> n >> m;
vector<int>a(n);
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
sort(a.begin(), a.end()); //从小到大排序
queue<int>arr; //用队列进行滑动窗口,要使用单调队列,及队列里的数具有单调性
ll ans = 0;
ll num = 0;
for (int i = 0; i < n; i++) //遍历花朵
{
while (arr.size() && (a[i] - arr.front() > 1 || a[i] + num > m)) { //当队列里面有数或者相差大于1以及钱不够,则弹出队列的首位
num -= arr.front();
arr.pop();
}
if (a[i] + num <= m) //这种情况其实是队列都被弹完了,但是要买的花瓣钱必须得够。
{
arr.push(a[i]);
num += a[i];
ans = max(ans, num);
}
}
cout << ans << endl;
}
return 0;
}