D. Eating
题目链接👈
题目描述🥰
题目思路😀
对于这个题目,暴力是不可行的,数据量过大会超时😇,同时这道题的思路也是非常的巧妙,以致于我补题补了两个小时(bushi)😰
首先注意,如果我们无法吃下一个史莱姆,那么这个史莱姆的最高有效位必须至少与当前的 x值一样大。这意味着,如果一个史莱姆的最高有效位严格小于x的最高有效位,我们总是可以吃掉它。
所以我们从最右边开始吃,我们可以直接找到大于等于x的最高有效位的史莱姆的下标,这个中间的史莱姆都是可以吃掉的,然后可以对于这个大于等于x的最高有效位的史莱姆进行判断,来判断x可不可以吃掉这个史莱姆。
如果吃不了就可以退出了。
因为思路很简单,但是代码的实现可能有点麻烦,所以我把核心部分代码拆开讲一下
首先 我们需要定义一个前缀数组,记录的是前i个元素的按位异或值(为了方便后面的吃操作)
vector<int>pre(n+1);
pre[0]=a[0];
for(int i=1;i<n;i++)pre[i]=pre[i-1]^a[i];
其次我们需要定义一个二维数组,f[i][j]表示的就是从0~i个数里面第j位为1的最右下标。
vector<vector<int>> f(n,vector<int>(30));
for(int i=0;i<n;i++)
{
fill(f[i].begin(), f[i].end(),0);
if(i)f[i]=f[i-1];
int x=__lg(a[i]);
f[i][x]=i;
//更新状态
for(int j=W-2;j>=0;j--)f[i][j]=max(f[i][j],f[i][j+1]);
}
对于里面的更新逻辑的讲解:(这个更新是如果存在第 j + 1
位及更高位为 1
,同时第 j
位也为 1
的情况,这样就可以及时更新f[i][j]
for(int j=W-2;j>=0;j--)f[i][j]=max(f[i][j],f[i][j+1]);
从次高位开始向低位遍历。对于 f[i][j]
,如果 f[i][j + 1]
大于 f[i][j]
,说明在 f[i][j + 1]
这个位置及其右侧,存在一个史莱姆重量的二进制表示中,不仅第 j + 1
位及更高位为 1
,同时第 j
位也为 1
。此时用 max(f[i][j], last[i][j + 1])
更新 f[i][j]
,可以保证 f[i][j]
始终记录的是第 j
位及更高位为 1
的最右侧史莱姆下标。
int x;
cin>>x;
int idx=n-1;
while(idx>=0&&x>0)
{
int msb=__lg(x);
int nx=f[idx][msb];
x^=(pre[idx]^pre[nx]);
idx=nx;
if(nx==-1||a[nx]>x)break;
x^=a[nx];
idx--;
}
cout<<n-1-idx<<" ";
这个代码就是在边界里面的找大于等于x的最高有效位的史莱姆的下标,因为中间的史莱姆是可以吃掉的,所以可以直接x^=(pre[idx]^pre[nx]),然后可以对于这个大于等于x的最高有效位的史莱姆进行判断,来判断x可不可以吃掉这个史莱姆,如果吃不了就可以退出了。
AC代码🧠
// Problem: D. Eating
// Contest: Codeforces - Codeforces Round 1005 (Div. 2)
// URL: https://codeforces.com/contest/2064/problem/D
// Memory Limit: 512 MB
// Time Limit: 5000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define dev1(a) cout << #a << '=' << a << endl;
#define dev2(a, b) cout << #a << " = " << a << " " << #b << " = " << b << endl;
#define dev3(a, b, c) cout << #a << " = " << a << " " << #b << " = " << b << " " << #c << " = " << c << endl;
#define dev4(a, b, c, d) cout << #a << " = " << a << " " << #b << " = " << b << " " << #c << " = " << c << " " << #d << " = " << d << endl;
#define dev5(a, b, c, d, e) cout << #a << " = " << a << " " << #b << " = " << b << " " << #c << " = " << c << " " << #d << " = " << d << " " << #e << " = " << e << endl;
#define vec(a) \
for (int i = 0; i < a.size(); i++) \
cout << a[i] << ' '; \
cout << endl;
#define darr(a, _i, _n) \
cout << #a << ':'; \
for (int ij = _i; ij <= _n; ij++) \
cout << a[ij] << ' '; \
cout << endl;
#define cin(a,n) \
for(int i=0;i<n;i++) \
cin>>a[i];
#define endl "\n"
#define pow pim
int pim(int a,int k)
{
int res=1;
if(a==0)return 0;
while(k)
{
if(k&1)res=(int)res*a;
k>>=1;
a=(int)a*a;
}
return res;
}
#define fi first
#define se second
#define caseT \
int T; \
cin >> T; \
while (T--)
#define int long long
// #define int __int128
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int MOD = 99999999;
const int N = 2e5+10;
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
int lcm(int a, int b)
{
return a * b / gcd(a, b);
}
inline int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int W=30;
void solve()
{
int n,q;
cin>>n>>q;
vector<int>a(n);
for(auto &x:a)cin>>x;
// f[i][j]表示的就是从0~i个数里面第j位为1的最右下标
vector<int>pre(n+1);
pre[0]=a[0];
for(int i=1;i<n;i++)pre[i]=pre[i-1]^a[i];
vector<vector<int>> f(n,vector<int>(30));
for(int i=0;i<n;i++)
{
fill(f[i].begin(), f[i].end(),0);
if(i)f[i]=f[i-1];
int x=__lg(a[i]);
f[i][x]=i;
//更新状态
for(int j=W-2;j>=0;j--)f[i][j]=max(f[i][j],f[i][j+1]);
}
while(q--)
{
int x;
cin>>x;
int idx=n-1;
while(idx>=0&&x>0)
{
int msb=__lg(x);
int nx=f[idx][msb];
x^=(pre[idx]^pre[nx]);
idx=nx;
if(nx==-1||a[nx]>x)break;
x^=a[nx];
idx--;
}
cout<<n-1-idx<<" ";
}
cout<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
caseT
solve();
return 0;
}
/*
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)