A - Diagonals
题意
思路
贪心,先将占有单元格最多的对角线填满,然后依次往下填。直接暴力或者二分都行。
代码
// Problem: A. Diagonals
// Contest: Codeforces - Codeforces Round 961 (Div. 2)
// URL: https://codeforces.com/contest/1995/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >mi;//小根堆
priority_queue<LL> ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vector<int>a(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
void solve()
{
int n , k;
cin >> n >> k;
int ans = 0;
if(k >= n){
ans++;
k -= n;
}
n -= 1;
while(n > 0 && k > 0){
if(k >= 2 * n){
k -= 2 * n;
ans += 2;
}
else{
ans += (k - 1) / n + 1;
k = 0;
}
n--;
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
B2 - Bouquet (Hard Version)
题意
思路
根据题意,最多可以选择两种不同的花购买。若只选一种花,那么就用这
m
m
m个金币买尽可能多的花即可。若选了两种花,我们可以先用这
m
m
m枚金币买尽可能多的价格少的那一种花,然后再用剩下的钱买尽可能多的价格多的那一种花。那么接下来,要么花全部买完了,要么剩下的钱不足以买下任意一朵花。
然后,我们可以通过放弃价格少的一种花,再购买价格多的那一种花,使得所得到的花瓣加
1
1
1。每次执行这一个操作可以使得花瓣加
1
1
1,接下来我们只需要求最多可以执行多少次这样的操作即可,然后便可以求出最大的花瓣数。
代码
// Problem: B2. Bouquet (Hard Version)
// Contest: Codeforces - Codeforces Round 961 (Div. 2)
// URL: https://codeforces.com/contest/1995/problem/B2
// Memory Limit: 256 MB
// Time Limit: 1500 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
#define int long long
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >mi;//小根堆
priority_queue<LL> ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vector<int>a(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
void solve()
{
int n , M;
cin >> n >> M;
vector< pair<int,int> > v;
int a[n] , b[n];
for(int i = 0 ; i < n ; i ++)
cin >> a[i];
for(int i = 0 ; i < n ; i ++)
cin >> b[i];
for(int i = 0 ; i < n ; i ++){
pl tmp;
tmp.x = a[i];
tmp.y = b[i];
v.pb(tmp);
}
sort(v.begin() , v.end());
int ans = M;
for(int i = 0 ; i < n ; i ++){
ans = min(ans , M - min(M / v[i].first , v[i].second) * v[i].first);
if(i > 0 && v[i].first - v[i - 1].first == 1){
int m = M;
int mx = min(M / v[i - 1].first , v[i - 1].second);
m -= mx * v[i - 1].first;
int t = min(m / v[i].first , v[i].second);
int res = v[i].second - t;
res = min(res , mx);
m -= t * v[i].first;
ans = min(ans , max(0LL , m - res));
}
}
cout << M - ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
C - Squaring
题意
思路
一次操作可以理解成将自己平方,或者将前一个数开根号。由于平方很容易越界,所以我们不主动改变
a
a
a数组的值,而是记录前一个数操作了几次。
若
a
i
<
a
i
−
1
a_{i} < a_{i-1}
ai<ai−1,我们需要通过操作使得
a
i
1
<
<
x
>
=
a
i
−
1
a_{i}^{1 <<x} >= a_{i-1}
ai1<<x>=ai−1,
x
x
x既是我们需要的操作数。如果
a
i
−
1
a_{i-1}
ai−1已经操作了
y
y
y次,那么很容易发现我们需要
x
+
y
x+y
x+y次操作,特别的,当
a
i
=
1
a_{i}=1
ai=1时,无论如何都没法成功,因此输出
−
1
-1
−1.
若
a
i
−
1
≤
a
i
a_{i - 1} \leq a_{i}
ai−1≤ai,且
a
i
−
1
a_{i-1}
ai−1已经操作了
y
y
y次,那么我们可以考虑什么情况下可以减少
a
i
a_{i}
ai的操作数:若
a
i
−
1
2
<
=
a
i
a_{i-1}^2 <= a_{i}
ai−12<=ai,那么我们就可以将操作数减一,不断进行这样的尝试,知道操作数为
0
0
0或者
a
i
−
1
2
>
a
i
a_{i-1} ^2 > a_{i}
ai−12>ai为止。
然后将每一个数的操作数相加即可。
代码
// Problem: C. Squaring
// Contest: Codeforces - Codeforces Round 961 (Div. 2)
// URL: https://codeforces.com/contest/1995/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
#define int long long
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >mi;//小根堆
priority_queue<LL> ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vector<int>a(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
void solve()
{
int ans = 0;
int n;
cin >> n;
for(int i = 1 ; i <= n ; i ++){
cin >> a[i];
}
int pre = 0;
for(int i = 1 ; i <= n ; i ++){
if(a[i] >= a[i - 1]){
int tmp = a[i - 1];
while(pre > 0 && tmp * tmp <= a[i]){
pre--;
tmp *= tmp;
}
ans += pre;
}
else{
int tmp = a[i];
if(tmp == 1){
cout << -1 << endl;
return;
}
while(tmp < a[i - 1]){
pre++;
tmp *= tmp;
}
ans += pre;
}
// cout << pre << endl;
}
cout << ans <<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
D - Cases
题意
思路
观察到字母数很少,因此我们可以用二进制压缩来表示每一种字母选择是否可以为正确答案。
接下来考虑什么样的字母组合没法构成答案:
1、不包含最后一个字母一定要在集合当中
2、若某个位置是
a
a
a,
b
b
b字母在这之后没有出现过或者距离大于
k
k
k,且下一个
a
a
a的距离也同样大于
k
k
k。那么只有
a
、
b
a、b
a、b同时选的情况就不可能成为答案,因此我们必然要在
a
,
b
a,b
a,b的位置之间选一个别的字母。
因此我们只需要从后往前遍历所有位置,然后统计哪些集合是没法选的,最终在剩下的集合中选一个所含字母最少的即可。
注意到:若一个集合没法选,那么其子集也同样没法被选中。因此我们对于每一个位置,只需要将最大的那个集合设为不可选,然后最终将大集合中的所有小集合同步更新即可。
代码
// Problem: D. Cases
// Contest: Codeforces - Codeforces Round 961 (Div. 2)
// URL: https://codeforces.com/problemset/problem/1995/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >mi;//小根堆
priority_queue<LL> ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vector<int>a(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
void solve()
{
int n , c , k;
cin >> n >> c >> k;
string s;
cin >> s;
vector<int>f(1 << c);
vector<int>nex(c , n);
for(int i = n - 1 ; i >= 0 ; i --){
int x = s[i] - 'A';
if(i == n - 1){
f[(1 << c) - (1 << x) - 1]++;
}
else{
int mask = 0;
for(int j = 0 ; j < c ; j ++){
if((nex[j] == n || nex[j] - i > k)){
mask |= 1 << j;
}
}
if(mask >> x & 1)
f[mask | 1 << x]++;
//f[mask]--;
}
nex[s[i] - 'A'] = i;
}
int mask = 0;
for(int j = 0 ; j < c ; j ++){
if((nex[j] == n || nex[j] >= k)){
mask |= 1 << j;
}
}
f[mask]++;
for(int i = 1 ; i < (1 << c) ; i *= 2){
for(int j = 0 ; j < (1 << c) ; j += 2 * i){
for(int k = 0 ; k < i ; k ++){
f[j + k] += f[i + j + k];
}
}
}
int ans = c;
for(int s = 0 ; s < (1 << c) ; s ++){
if(f[s] == 0){
ans = min(ans , __builtin_popcount(s));
}
}
cout << ans <<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}