A. Diagonals
根据题目定义对角线显然从左上到右下,那么显然一个n*n的矩形有2n-1个对角线,把所有对角线取出后排序为n,n-1,n-1,n-2,n-2...1,1,从大到小用m减去即可。
#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define rep(x,a,b) for(int x=a;x<=b;x++)
#define pre(x,a,b) for(int x=a;x>=b;x--)
#define ac puts("Yes")
#define wa puts("No")
#define ll long long
#define endl "\n"
#define pb push_back
#define pii pair<int, int>
#define de cout<<1;
#define mem(a,x) memset(a,x,sizeof a)
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define ull unsigned long long
#define eps 1e-6
#define RI register int
#define CI const int&
using namespace std;
const int mod=1e9 + 7;
const int N = 2e5 + 20;
int n, m;
int a[N];
void solve()
{
cin >> n >> m;
int idx = 0;
a[++idx] = n;
pre(i, n - 1, 1)
{
a[++idx] = i;
a[++idx] = i;
}
int cnt = 0;
rep(i, 1, idx)
{
if(m <= 0) break;
m -= a[i];
cnt ++ ;
}
cout << cnt << endl;
}
int main()
{
IOS;
int t;
t = 1;
cin >> t;
while(t -- )
{
solve();
}
return 0;
}
B2. Bouquet (Hard Version)
这题赛时直接去写hard了,仅提供hard的做法。
由于组合的花花瓣差不超过1,因此用map统计一下花瓣数为x的花有多少个,然后遍历一遍,对于两个差为1的,我们优先用花瓣数小的,因为这样会发现当优先使用小的那个去填不够的用大的补,会发现在塞不下之后可以通过去掉一个小的,换上一个大的,从而使得答案加一,因此只需要先用小的然后算出能换多少大的即可。
#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define rep(x,a,b) for(int x=a;x<=b;x++)
#define pre(x,a,b) for(int x=a;x>=b;x--)
#define ac puts("Yes")
#define wa puts("No")
#define int long long
#define endl "\n"
#define pb push_back
#define pii pair<int, int>
#define de cout<<1;
#define mem(a,x) memset(a,x,sizeof a)
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define ull unsigned long long
#define eps 1e-6
#define RI register int
#define CI const int&
using namespace std;
const int mod=1e9 + 7;
const int N = 2e5 + 20;
int n, m;
int a[N], b[N];
void solve()
{
cin >> n >> m;
rep(i, 1, n) cin >> a[i];
rep(i, 1, n) cin >> b[i];
map<int, int>mp;
rep(i, 1, n) mp[a[i]] += b[i] ;
int last = 0, ans = 0;
for(auto [x, y] : mp)
{
int cnt = m / x;
cnt = min(cnt, y);
ans = max(ans, cnt * x);
if(!last) last = x;
else if(x - last == 1)
{
int ct = m / last;
ct = min(ct, mp[last]);
int tt = m - ct * last;
int ttt = y;
if(tt >= x)
{
int ndd = tt / x;
ndd = min(ndd, y);
ttt -= ndd;
tt -= ndd * x;
}
//if(last == 206)cout<<tt;
int nd = min(tt, min(ct, ttt));
tt -= nd;
ans = max(ans, m - tt);
}
last = x;
}
cout << ans << endl;
}
signed main()
{
IOS;
int t;
t = 1;
cin >> t;
while(t -- )
{
solve();
}
return 0;
}
C. Squaring
可以发现直接贪心就是最后的答案,可是难点在于比较相邻两个数的大小,因为操作次数多会爆longlong。因为a的大小只有1e6,因为如果那么
最多需要5次操作就可以比前一个数大,那么此时在使用和前一个数一样多的操作就可以保证大于前一个数,因此当前的数最多只比前一个数多操作5次。直接暴力枚举操作数即可。为了防止爆longlong当前使用的次数可以用前一个数减去来比较。
#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define rep(x,a,b) for(int x=a;x<=b;x++)
#define pre(x,a,b) for(int x=a;x>=b;x--)
#define ac puts("Yes")
#define wa puts("No")
#define ll long long
#define endl "\n"
#define pb push_back
#define pii pair<int, int>
#define de cout<<1;
#define mem(a,x) memset(a,x,sizeof a)
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define ull unsigned long long
#define eps 1e-6
#define RI register int
#define CI const int&
using namespace std;
const int mod=1e9 + 7;
const int N = 1e6 + 20;
int n, m;
int a[N];
int sum[N];
double mp[N];
long long mpp[N];
double l2[N];
void solve()
{
scanf("%d", &n);
rep(i, 1, n) scanf("%d", &a[i]), sum[i] = 0;
rep(i, 2, n)
{
if(a[i] < a[i - 1] && a[i] == 1)
{
printf("-1\n");
return;
}
}
rep(i, 2, n)
{
int x = max(0, sum[i - 1] - 20);
while((double)pow(a[i - 1], (double)pow(2, (double)sum[i - 1] - x)) > 1.0 * a[i] && x < sum[i - 1] + 5)
{
x ++ ;
}
sum[i] = x;
}
long long ans = 0;
rep(i, 1, n) ans += sum[i];
printf("%lld\n", ans);
}
int main()
{
int t;
t = 1;
scanf("%d", &t);
while(t -- )
{
solve();
}
return 0;
}
D. Cases
范围明显是状压dp,考虑如何设计。
题目要求每k个连续的子串都至少有一个结尾字母,那么显然对于一段连续k个字母的子串,如果其中的每种字母在整个串都没有作为结尾出现那么一定是不合法的。如果最后一个字母不是结尾那一定也不合法。设一个状态s,s的二进制位为1表示这一位代表的字母没有作为结尾。那么刚才提到的两个不合法状态就可以初始化为0,其余状态初始化为1。最后集合从小到大枚举,看当前集合是否有不合法的子集即可。答案就是合法集合中二进制位0最少的个数。
#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define rep(x,a,b) for(int x=a;x<=b;x++)
#define pre(x,a,b) for(int x=a;x>=b;x--)
#define ac puts("Yes")
#define wa puts("No")
#define ll long long
#define endl "\n"
#define pb push_back
#define pii pair<int, int>
#define de cout<<1;
#define mem(a,x) memset(a,x,sizeof a)
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define ull unsigned long long
#define eps 1e-6
#define RI register int
#define CI const int&
using namespace std;
const int mod=1e9 + 7;
const int N = 1e6 + 20;
int n, m, k;
int a[N], dp[1 << 18];
void solve()
{
cin >> n >> m >> k;
rep(i, 0, (1 << m) - 1) dp[i] = 1;
string s;
cin >> s;
s = " " + s;
int now = 0;
map<char, int>mp;
rep(i, 1, n)
{
mp[s[i]] ++ ;
now |= (1 << (s[i] - 'A'));
if(i - k > 0)
{
mp[s[i - k]] -- ;
if(mp[s[i - k]] == 0) now -= (1 << (s[i - k] - 'A'));
}
if(i >= k) dp[now] = 0;
}
rep(i, 0, (1 << m) - 1)
{
if(i >> (s[n] - 'A') & 1) dp[i] = 0;
}
rep(i, 0, (1 << m) - 1)
{
rep(j, 0, m - 1)
{
if(i >> j & 1) dp[i] &= dp[i - (1 << j)];
}
}
int ans = 100;
rep(i, 0, (1 << m) - 1)
{
if(dp[i])
{
int cnt = 0;
rep(j, 0, m - 1)
{
if(!(i >> j & 1)) cnt ++ ;
}
ans = min(ans, cnt);
}
}
cout << ans << endl;
}
int main()
{
int t;
t = 1;
cin >> t;
while(t -- )
{
solve();
}
return 0;
}