2025牛客寒假算法基础集训营6 个人补题 ACIJKL
A-复制鸡_2025牛客寒假算法基础集训营6
思路:注意到拓展的数都是前面后续延伸的一部分,所以把连续区间归一即可,使用栈或者双端队列,双指针均可解决
// Code Start Here
int t;
cin >> t;
while(t--){
int n;
cin >> n;
deque<int> dq(n);
for(auto &it : dq)cin >> it;
int cnt = 0;
while(!dq.empty()){
int now = dq.front();
while(!dq.empty() && dq.front() == now)dq.pop_front();
cnt++;
}
cout << cnt<< endl;
}
C-数列之和_2025牛客寒假算法基础集训营6
首先观察到k < 1e18,而a有1e100个数,长度大于1的连续子序列前1e100-1项都是挑两个连续的数。而K又一定在这由两个数组成的区间内
综上答案显而易见了,直接模拟即可
LL power(LL a ,LL t){
LL res = a;
for(int i = 2;i<=t;i++){
res *= a;
}
return res;
}
int32_t main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
// Code Start Here
int t;
cin >> t;
while(t--){
LL k;
cin >> k;
if(k == 1){
cout << "2\n";
continue;
}
LL sum = 0;
LL ans = 0;
for(int i = 2;power(2,i)<=2*k;i++){
sum ++;
ans = i;
}
if(2 * k + 2 * sum >= power(2,ans+1))cout << 2 * (k + sum + 1) << endl;
else cout << 2 * ( k + sum) << endl;
}
return 0;
}
I-小鸡的排列构造的checker_2025牛客寒假算法基础集训营6
牛客竞赛出题组的题解给的很清晰
本题预期的做法是使用离线将查询排序的技巧,使用树状数组进行维护。
我们举一个例子说明该做法的思路,例如输入的数组 ppp 为 [1,3,2,4,5],查询分别为 [1,5,2]和 [2,5,4],我们发现 [1,5,2][1,5,2][1,5,2] 查询相当于在问: [1,5] 区间里有多少个小于等于 p2 的数字?(因为这些数的个数能得出排序后 p2的位置)。
于是我们可以维护一个初始全 0 的树状数组,按照 pi从小到大给树状数组的对应位置 +1,也就是在上述例子中,树状数组维护的原数组依次是:
状态1:[1,0,0,0,0] 状态2:[1,0,1,0,0] 状态3:[1,1,1,0,0]状态4:[1,1,1,1,0]状态5:[1,1,1,1,1]
这样询问 [1,5,2]其实是在对状态2的数组求 [1,5] 区间的和,使用树状数组可以做到;询问 [2,5,4]其实是在对状态4的数组求 [2,5]区间的和,使用树状数组可以做到。
因此,像上述过程一样,把所有 [l,r,c]询问按照 p[c] 从小到大排序,树状数组维护上述过程即可,复杂度 O(nlogn)。
/*
by lr580
Last built at 2024/6/5
可持久化线段树
*/
#define lg 22
#define mn 200010
ll m, n, q, a[mn], l[mn * lg], r[mn * lg], v[mn * lg], rot[mn], lc, rc, k,cnt, a0[mn],idx;
#define mkcf ll cf = (lf + rf) >> 1
ll build(ll lf, ll rf)
{
ll p = ++cnt;
if (lf != rf)
{
mkcf;
l[p] = build(lf, cf);
r[p] = build(cf + 1, rf);
}
return p;
}
ll update(ll q, ll lf, ll rf)
{
ll p = ++cnt;
l[p] = l[q], r[p] = r[q], v[p] = v[q] + 1;
if (lf != rf)
{
mkcf;
if (k <= cf)
{
l[p] = update(l[q], lf, cf);
}
else
{
r[p] = update(r[q], cf + 1, rf);
}
}
return p;
}
ll query(ll p, ll q, ll lf, ll rf, ll i)
{
if (lf == rf)
{
return lf;
}
mkcf;
ll j = v[l[q]] - v[l[p]];
if (j >= i)
{
return query(l[p], l[q], lf, cf, i);
}
else
{
return query(r[p], r[q], cf + 1, rf, i - j);
}
}
ll count(ll p, ll q, ll lf, ll rf, ll x) {
if(rf < x) return v[q] - v[p];
if(lf >= x) return 0;
mkcf;
return count(l[p], l[q], lf, cf, x) + count(r[p], r[q], cf+1, rf, x);
}
int32_t main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
// Code Start Here
int t;
cin >> t;
while(t--){
cin >> n >> m;
for(int i = 1;i<=n;i++){
cin >> a0[i];
a[i] = a0[i];
}
sort(a+1,a+1+n);
ll alls = unique(a+1,a+1+n) - (a+1);
cnt = 0;
rot[0] = build(1,alls);
for(int i = 1;i<=n;i++){
k = lower_bound(a+1,a+1+alls,a0[i]) - a;
// cout << "k:" << k << endl;
rot[i] = update(rot[i-1],1,alls);
// cout << "i :" << i <<"rot[i] :" << rot[i] << endl;
}
while(m--){
cin >> lc >> rc >> idx;
ll x = lower_bound(a + 1 , a+1+alls,a0[idx]) - a;
ll sm = count(rot[lc-1],rot[rc],1,alls,x);
cout << lc + sm <<endl;
}
}
return 0;
}
J-铁刀磨成针_2025牛客寒假算法基础集训营6
最朴素的想法:在 n
个回合内最大化总伤害,考虑两种行动:
1、磨刀(每回合最多一次): 使攻击力 +1
,消耗 y
个磨刀石中的一个。
2、攻击(每回合最多一次): 对敌方造成 当前攻击力
的伤害,并使攻击力 -1
,直到攻击力降为 0。
我们枚举 0 到 y
次磨刀操作,计算每种情况下的最大伤害,注意到磨刀在初始的时候最大化伤害
磨刀 i
次后,刀的初始攻击力变为 x + i
。
剩余 y
次内可以选择攻击,造成 (x + i + 1) * (y - i)
伤害。
磨刀石用完后,继续攻击直到刀坏,造成 等差数列求和 (l + g) * (g - l + 1) / 2
的伤害。
最终在所有 i
的方案中取最大值。
时间复杂度On^2可以接受
主要难度在于转化模型的过程
// Code Start Here
int t;
cin >> t;
while(t--){
int n, x, y;
cin >> n >> x >> y;
int maxDamage = 0;
for (int i = 0; i <= y; i++) {
int atk = x + i;
int roundsUsed = i;
int damage = 0;
// 用尽磨刀石时的伤害
if (roundsUsed < n) {
damage += (atk + 1) * min(y - i, n - i);
roundsUsed += min(y - i, n - i);
}
// 继续攻击直到刀坏
if (roundsUsed < n) {
int l = max(1LL, atk - (n - roundsUsed) + 1);
damage += (l + atk) * (atk - l + 1) / 2;
}
maxDamage = max(maxDamage, damage);
}
cout << maxDamage << '\n';
}
K-鸡翻题_2025牛客寒假算法基础集训营6
模拟题,根据当前页数模拟即可
// Code Start Here
int t;
cin >> t;
while(t--){
LL x , y;
cin >>x >> y;
if((x % 2 == 0 && y % 4 == 1) ||(x % 2 == 1 && y % 4 == 3))cout <<"YES\n";
else cout <<"NO\n";
}
L-变鸡器_2025牛客寒假算法基础集训营6
最坑的地方是:任意两个不同字符
首先注意到如果 < 7或者剩下奇数肯定不行,然后就是看剩下的能不能组成chicken和是不是两两配对即可
// Code Start Here
int t;
cin >> t;
while(t--){
int n;
cin >> n;
string s;
cin >> s;
if(n < 7 || ((n - 7) % 2 != 0)){
cout << "NO\n";
continue;
}
string tar = "CHICKEN";
int j = 0;
for (int i = 0; i < n && j < sz(tar); i++)if(s[i] == tar[j])j++;
if(j != sz(tar)){
cout << "NO\n";
continue;
}
vector<int> f(30, 0);
for(char c : s){
f[c - 'A']++;
}
vector<int> r(30, 0);
for(char c : tar){
r[c - 'A']++;
}
bool flag = true;
for (int c = 0; c < 26; c++){
if(r[c] > f[c]){
flag = false;
break;
}
int re = (r[c] > 0) ? (f[c] - r[c]) : f[c];
if(re > (n - 7) / 2){
flag = false;
break;
}
}
cout << (flag ? "YES" : "NO") << "\n";