A. Diagonals
题目
给 Vitaly503 一个方格棋盘,棋盘的一边有 n n n 和 k k k 个筹码。他意识到所有这些 k k k 芯片都需要放置在棋盘的单元格上(一个单元格上不能放置超过一个芯片)。
让我们把第 i i i 行和第 j j j 列中的单元格表示为 ( i , j ) (i ,j) (i,j) 。对角线是指 i + j i + j i+j 值相同的单元格集合。例如,单元格 ( 3 , 1 ) (3, 1) (3,1) 、 ( 2 , 2 ) (2, 2) (2,2) 和 ( 1 , 3 ) (1, 3) (1,3) 位于同一条对角线上,但 ( 1 , 2 ) (1, 2) (1,2) 和 ( 2 , 3 ) (2, 3) (2,3) 不在同一条对角线上。如果一条对角线上至少包含一个棋子,那么这条对角线就被称为 "被占 "对角线。
请计算在所有放置 k k k 的筹码中,被占对角线的最少数目。
输入
每个测试由多组输入数据组成。第一行包含一个整数 t t t ( 1 ≤ t ≤ 500 1 \le t \le 500 1≤t≤500 ) - 输入数据集的数量。然后是各组输入数据的说明。
每组输入数据的唯一一行包含两个整数 n n n , k k k ( 1 ≤ n ≤ 100 , 0 ≤ k ≤ n 2 1 \le n \le 100, 0 \le k \le n^2 1≤n≤100,0≤k≤n2 )( 1 ≤ n ≤ 100 , 0 ≤ k ≤ n 2 1 \le n \le 100, 0 \le k \le n^2 1≤n≤100,0≤k≤n2 ) - 分别是棋盘的边数和可用筹码数。
输出
对于每组输入数据,输出一个整数--在放置所有 k k k 个筹码后,他能得到的至少有一个筹码的对角线的最小占位数。
解题思路
cpp
![如图](https://i-blog.csdnimg.cn/direct/dd61373bc85e4a2c8624a490402059bc.jpeg#pic_center)
画图可得
有 1 条长度为 n 的对角线,有 2 条长度为 (1~n-1) 的对角线
AC代码
cpp
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fi first
#define se second
#define PII pair<int,int>
#define ALL(x) x.begin(),x.end()
const int N=2e5+10;
void solve()
{
int ans=0;
int n,k;cin>>n>>k;
if(k==0)
{
cout<<"0\n";
return;
}
for(int i=n;i>=1;i--)
{
if(i==n)
{
ans++;
k-=n;
continue;
}
if(k<=0)break;
ans++;
k-=i;
if(k<=0)break;
ans++;
k-=i;
}
cout<<ans<<'\n';
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--)solve();
return 0;
}
B1. Bouquet (Easy Version)
题目
这是问题的简单版本。唯一不同的是,在这个版本中,花朵是通过枚举来指定的。
一个女孩准备过生日,想买一束最漂亮的花。商店里一共有 n n n 种花,每种花的特征是花瓣数,一朵有 k k k 个花瓣的花需要花费 k k k 枚硬币。女孩决定,花束中任何两朵花的花瓣数之差都不能超过 1。同时,女孩希望花束的花瓣数尽可能多。不幸的是,她只有 m m m 枚金币,不能再花更多的钱。她能组合的花束的花瓣总数最多是多少?
输入
每个测试由多个测试用例组成。第一行包含一个整数 t t t ( 1 ≤ t ≤ 10 000 1 \le t \le 10\,000 1≤t≤10000 ) - 测试用例数。随后是测试用例的说明。
每个测试用例的第一行包含两个整数 n n n , m m m ( 1 ≤ n ≤ 2 ⋅ 1 0 5 , 1 ≤ m ≤ 1 0 18 1 \le n \le 2 \cdot 10^5, 1 \le m \le 10^{18} 1≤n≤2⋅105,1≤m≤1018 ) --分别是商店里的鲜花数量和女孩拥有的硬币数量。每个测试用例的第二行包含 n n n 个整数 a 1 , a 2 , ... , a n a_1, a_2, \ldots, a_n a1,a2,...,an ( 1 ≤ a i ≤ 1 0 9 1 \le a_i \le 10^9 1≤ai≤109 ),其中 a i a_i ai 是商店里第 i i i 朵花的花瓣数。
所有测试用例的 n n n 之和不超过 2 ⋅ 10 5 2 \cdot {10}^5 2⋅105 。
输出
对于每个测试用例,输出一个整数,即在满足上述所有条件的情况下,女孩在花束中可能组合的最大花瓣数。
解题思路
cpp
用队列维护先后顺序,不符合题意就出队
AC代码
cpp
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10;
int a[N];
void solve()
{
int n,m;cin>>n>>m;
memset(a,0,sizeof(a));
int sum=0,ma=0;
queue<int>q;
for(int i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
for(int i=0;i<n;i++)
{
q.push(a[i]); // 入队
sum+=a[i]; // 累加
while(!q.empty()&&a[i]>(q.front()+1)) // 大于 1个 花瓣数出队
{
sum-=q.front();
q.pop();
}
while(!q.empty()&&sum>m) // 总和大于 m ,出队
{
sum-=q.front();
q.pop();
}
if(sum<=m)
ma=max(ma,sum); // 每次变化,求最大值
}
cout<<ma<<'\n';
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--)solve();
return 0;
}
B2. Bouquet (Hard Version)
题目
**这是问题的困难版本。唯一不同的是,在这个版本中,不是列出每种花的花瓣数,而是为所有类型的花设置花瓣数和商店中的花的数量。
一个女孩准备过生日,想买一束最漂亮的花。店里一共有 n n n 种不同类型的花,每种花都有花瓣数和数量。花瓣数为 k k k 的花朵售价为 k k k 枚金币。女孩决定,她用来装饰蛋糕的任何两朵花的花瓣数之差都不能超过 1。同时,女孩还想用尽可能多的花瓣组合成一束花。不幸的是,她只有 m m m 枚金币,无法再花费更多。她能组合的花束花瓣总数最多是多少?
输入
每个测试由多个测试用例组成。第一行包含一个整数 t t t ( 1 ≤ t ≤ 10 000 1 \le t \le 10\,000 1≤t≤10000 ) - 测试用例数。随后是测试用例的说明。
每个测试用例的第一行包含两个整数 n n n , m m m ( 1 ≤ n ≤ 2 ⋅ 1 0 5 , 1 ≤ m ≤ 1 0 18 1 \le n \le 2 \cdot 10^5, 1 \le m \le 10^{18} 1≤n≤2⋅105,1≤m≤1018 )--分别是商店中鲜花的种类数和女孩拥有的硬币数。每个测试用例的第二行包含 n n n 不同 的整数 a 1 , a 2 , ... , a n a_1, a_2, \ldots, a_n a1,a2,...,an ( 1 ≤ a i ≤ 1 0 9 1 \le a_i \le 10^9 1≤ai≤109 ),其中 a i a_i ai 是商店中 i i i /th 鲜花类型的花瓣数(对于不同索引 i ≠ j i \neq j i=j ,必须是 a i ≠ a j a_i \neq a_j ai=aj )。每个测试用例的第三行包含 n n n 个整数 c 1 , c 2 , ... , c n c_1, c_2, \ldots, c_n c1,c2,...,cn ( 1 ≤ c i ≤ 1 0 9 1 \le c_i \le 10^9 1≤ci≤109 ),其中 c i c_i ci 是商店中 i i i -th 种花的数量。
所有测试用例中 n n n 的总和不超过 2 ⋅ 10 5 2 \cdot {10}^5 2⋅105 。
输出
对于每个测试用例,打印一个整数 - 在遵守上述所有条件的情况下,女孩在花束中可能收集到的最大花瓣数。
解题思路
cpp
由任何两朵花的花瓣数之差都不能超过 1 得,维护在遵守上述所有条件的情况下,只有一种花,或者有两种花瓣数差 1 的花
让花瓣数多的花数量达到合理的最多
AC代码
cpp
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
#define fi first
#define se second
#define ALL(x) x.begin(),x.end()
void solve()
{
int n,m;cin>>n>>m;
vector<PII >q(n);
for(int i=0;i<n;i++) cin>>q[i].fi;
for(int i=0;i<n;i++) cin>>q[i].se;
int ans=0;
sort(ALL(q));
ans=min(m/q[0].fi,q[0].se)*q[0].fi;
for(int i=1;i<n;i++)
{
if(q[i].fi-q[i-1].fi==1) // 满足差为 1
{
int num1=min(m/q[i-1].fi,q[i-1].se); //初使花瓣少的最多
int num2=min((m-q[i-1].fi*num1)/q[i].fi,q[i].se);
int re=m-num2*q[i].fi-num1*q[i-1].fi;
int r=min(re,min(num1,q[i].se-num2)); // 花瓣数少 转化成 花瓣数多
ans=max(ans,q[i].fi*(r+num2)+q[i-1].fi*(num1-r));
}
else // 不满足差为 1
ans=max(ans,min(q[i].se,m/q[i].fi)*q[i].fi);
}
cout<<ans<<'\n';
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t;cin>>t;
while(t--)solve();
return 0;
}
C. Squaring
题目
ikrpprpp 发现了一个由整数组成的数组 a a a 。他喜欢公正,所以想让 a a a 变得公平,也就是让它不递减。为此,他可以在数组的索引 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n 上执行一次公正行动,将 a i a_i ai 替换为 a i 2 a_i ^ 2 ai2 (位置 i i i 的元素与其平方)。例如,如果 a = [ 2 , 4 , 3 , 3 , 5 , 3 ] a = [2,4,3,3,5,3] a=[2,4,3,3,5,3] 和ikrpprpp选择对 i = 4 i = 4 i=4 执行正义行动,那么 a a a 就会变成 [ 2 , 4 , 3 , 9 , 5 , 3 ] [2,4,3,9,5,3] [2,4,3,9,5,3] 。
要使数组不递减,最少需要多少次正义行动?
输入
第一行包含一个整数 t t t ( 1 ≤ t ≤ 1000 1 \le t \le 1000 1≤t≤1000 )。( 1 ≤ t ≤ 1000 1 \le t \le 1000 1≤t≤1000 )--测试用例的数量。随后是测试用例说明。
对于每个测试用例,第一行包含一个整数 n n n - 数组的大小 a a a 。- 数组的大小 a a a 。第二行包含 n n n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10 ^5 1≤n≤2⋅105 ) 个整数 a 1 , a 2 , ... , a n a_1, a_2,\ldots, a_n a1,a2,...,an ( 1 ≤ a i ≤ 1 0 6 1 \le a_i \le 10 ^ 6 1≤ai≤106 )。
所有测试用例中 n n n 的总和不超过 2 ⋅ 10 5 2 \cdot {10}^5 2⋅105 。
输出
对于每个测试用例,打印一个整数--使数组 a a a 不递减所需的最小正义行为数。如果无法做到,则打印 − 1 -1 −1 。
解题思路
cpp
每一位继承前一位的平方次数,x<y,x 与 y 同时平方相同次数大小关系不变
AC代码
cpp
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define int long long
#define fi first
#define se second
#define PII pair<int,int>
#define ALL(x) x.begin(),x.end()
void solve()
{
int n;cin>>n;
vector<int >a(n+1);
vector<int >b(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=2;i<=n;i++)
{
if(a[i]==a[i-1]) // 与上一位相同时,直接继承上一位的平方次数
{
b[i]=b[i-1];
continue;
}
if(a[i]==1) // 特判,因为 1 的平方 等于 1
{
if(a[i-1]==1) continue; // 前一位为 1 合理
else // 前一位不为 1 ,不合理
{
cout<<"-1"<<'\n';
return;
}
}
if(a[i]>a[i-1]) // 符合升序条件,加上上一位的平方次数,减去上一位达到 x<y 的关系
{
if(a[i-1]==1)continue;
int x=a[i],y=a[i-1];
int tt=0;
while(y<=x)
{
y=y*y;
tt++;
}
b[i]=max(0ll,b[i-1]-tt+1); // 加上 1 达到 维护初始a[i-1]<a[i]
}
else // 不符合升序条件,达到 a[i-1]<a[i] ,并继承上一位的平方次数
{
int x=a[i],y=a[i-1];
int tt=0;
while(x<y)
{
x=x*x;
tt++;
}
b[i]=b[i-1]+tt;
}
}
int ans=0;
for(int i=1;i<=n;i++) ans+=b[i]; // 累加各个平方次数
cout<<ans<<'\n';
}
signed main()
{
IOS
int t;
cin>>t;
while(t--)solve();
return 0;
}