随笔- 19  文章- 0  评论- 0  阅读- 717 

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;
}
/*
   
     
*/

 

 posted on   熙玺  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)

Shu-How Zの小窝

Loading...
点击右上角即可分享
微信分享提示