bzoj 5092 [Lydsy1711月赛]分割序列——高维前缀和

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5092

套路地弄一个前缀异或和,就变成 f[ i ]=max_{j=0}^{i} { s[ j ] + (s[ i ]^s[ j ]) }。再套路地考虑按位贪心。

然后看了题解。按位贪心不是确定 f[ i ] 的这一位是0还是1,而是确定这一位是否给答案贡献 bin[ j ] !

按位考虑,自己这一位如果是1,则 j 不管取在哪,都只有一种情况,就是向答案贡献 bin[ j ];

  自己这一位如果是0,则 j 的位置影响到这一位对答案的贡献是 0 还是 2*bin[ j ] 。

因为自己这一位是0了,又要有那样的贡献,所以 j 的这一位一定是1;做到这一位的时候已经知道更高的位上选择了哪些位为1,所以如果知道自己位置是否可以在满足更高的选了1的位仍旧选1的基础上把这一位也选上1的话就好了。

这里有很好的思路:不是求自己能否达到,而是预处理整个数组里符合这个条件的最靠前的位置!这样自然也能判断自己是否可行了。

即,预处理满足更高位确定、当前位为1、更低位随便的a[ ]的最靠前位置。

这个可以用高维前缀和来做。初值是 p[ a[ i ] ]=min{ p[ a[ i ] ] , i } ,倒着枚举 i 就不用取min了;没有出现的值的 p 是 n+1 ,p[ 0 ] = 0。

状态里的 0 表示不作要求,1表示必须为1;则从低到高位枚举,p[ i ]对(最高位到当前位固定、当前位到最低位是自己子集)的p[ j ]取min即可。

计算答案的时候注意因为 a[ i ]&bin[ j ] 而产生贡献的,不用算在和 p 有关的那个限制里。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3e5+5,M=25,K=(1<<20)+5;//K!=1e6!!!
int n,a[N],bin[M],p[K];
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)fx=0;ch=getchar();}
  while(ch>=‘0‘&&ch<=‘9‘) ret=(ret<<3)+(ret<<1)+ch-‘0‘,ch=getchar();
  return fx?ret:-ret;
}
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
int main()
{
  int mx=0,lm;
  n=rdn();for(int i=1;i<=n;i++)a[i]=rdn()^a[i-1],mx=Mx(mx,a[i]);
  bin[0]=1;
  for(lm=1;(bin[lm-1]<<1)<=mx;lm++)
    bin[lm]=bin[lm-1]<<1;
  bin[lm]=bin[lm-1]<<1;
  for(int i=1;i<bin[lm];i++)p[i]=n+1;
  for(int i=n;i;i--)p[a[i]]=i;
  p[0]=0;
  for(int t=0;t<lm;t++)
    for(int i=1;i<bin[lm];i++)
      if(!(i&bin[t]))
    p[i]=Mn(p[i],p[i|bin[t]]);
  for(int i=1,ans=0,lj=0;i<=n;i++,ans=0,lj=0)
    {
      for(int j=lm-1;j>=0;j--)
    {
      if(a[i]&bin[j])
        {ans+=bin[j];continue;}//no lj|=bin[j]
      if(p[lj|bin[j]]<=i)
        {
          ans+=bin[j]<<1;lj|=bin[j];
        }
    }
      printf("%d\n",ans);
    }
  return 0;
}

原文地址:https://www.cnblogs.com/Narh/p/10029879.html

时间: 2024-10-02 01:00:47

bzoj 5092 [Lydsy1711月赛]分割序列——高维前缀和的相关文章

bzoj 5092 分割序列 —— 高维前缀和

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5092 首先,处理出异或前缀和 s[i],i 位置的答案就是 s[j] + s[j]^s[i],j <= i 异或的套路是按位考虑,但是这里有加法...怎么考虑进位? 所以就不能考虑答案的这一位是什么,而应该考虑在这一位上的贡献,那么即使进位了,还是各位算各位的贡献,互相独立: 然后发现,如果 s[i] 在第 k 位上是1,那么 s[j] 的第 k 位无论是0还是1,总体的贡献都是 1<&

bzoj5092: [Lydsy1711月赛]分割序列

[题解] 理解得迷迷糊糊... 一些准备操作就不说了吧.. 首先对于当前的第i个数,贪心思想按二进制位从高到低考虑. 若当前第j位是1,不管异或0还是1,这一位的贡献肯定是1<<j,不考虑?? 对于当前位是0的情况,你只要考虑是否有数 包含 前面几位高位的被异或出来的1 的情况下,当前位也是1,那么就异或上当前的1,加上当前的1的贡献,也就是答案加上2<<j. 这里有个细节,处理第j位的时候,先不用管低位是否被影响到(可以思考一下). 主要是考虑怎么求出是否有满足条件的数. 这个只

bzoj 5093 [Lydsy1711月赛]图的价值 NTT+第二类斯特林数

[Lydsy1711月赛]图的价值 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 245  Solved: 128[Submit][Status][Discuss] Description “简单无向图”是指无重边.无自环的无向图(不一定连通). 一个带标号的图的价值定义为每个点度数的k次方的和. 给定n和k,请计算所有n个点的带标号的简单无向图的价值之和. 因为答案很大,请对998244353取模输出. Input 第一行包含两个正整数n,k(

SPOJ Time Limit Exceeded(高维前缀和)

[题目链接] http://www.spoj.com/problems/TLE/en/ [题目大意] 给出n个数字c,求非负整数序列a,满足a<2^m 并且有a[i]&a[i+1]=0,对于每个a[i],要保证a[i]不是c[i]的倍数, 求这样的a[i]序列的个数 [题解] 我们用dp[i]表示以i为结尾的方案数, 我们发现要满足a[i]&a[i+1]=0,则dp[i]是从上一次结果中所有满足i&j=0的地方转移过来的 i&j=0即i&(~j)=i,即i为~

CF449D Jzzhu and Numbers 高维前缀和

title CF449D Description 给出一个长度为 \(n\) 的序列 \(a_1,a_2...a_n\) . 求构造出一个序列 \(i_1 \le i_2 \le ... \le i_k\) 使得 \(a_{i_1}\&a_{i_2}\&...\&a_{i_k}=0\) .求方案数模 \(10^9+7\) . 也就是从 \(\{a_i\}\) 里面选出一个非空子集使这些数按位与起来为 \(0\) . analysis 这不是普转提的第四题吗?不得不防啊. 这也是一个

4.7-4.9补题+水题+高维前缀和

题目链接:51nod 1718 Cos的多项式  [数学] 题解: 2cosx=2cosx 2cos2x=(2cosx)^2-2 2cos3x=(2cosx)^3-3*(2cosx) 数归证明2cos(nx)能表示成关于2cosx的多项式,设为f(n) f(1)=x,f(2)=x^2-2(其中的x就是2cosx) 假设n=1~k时均成立(k>=3) 当n=k+1时 由cos((k+1)x)=cos(kx)cos(x)-sin(kx)sin(x) cos((k-1)x)=cos(kx)cos(x)

hihocoder1496(高维前缀和)

题意:给定N个数A1, A2, A3, ... AN,小Ho想从中找到两个数Ai和Aj(i ≠ j)使得乘积Ai × Aj × (Ai AND Aj)最大.其中AND是按位与操作. 第一行一个整数N(1<=N<=100,000) 第二行N个整数A1, A2, A3, ... AN (0 <= Ai <2^20) 分析: 尝试枚举and值z,那么问题就变成了找寻最大的x*y,使得x&y==z 把这个要求放宽一点,我们来寻找z是x&y子集的情况(这样肯定不会丢掉整体最优

Codeforces 449D:Jzzhu and Numbers(高维前缀和)

[题目链接] http://codeforces.com/problemset/problem/449/D [题目大意] 给出一些数字,问其选出一些数字作or为0的方案数有多少 [题解] 题目等价于给出一些集合,问其交集为空集的方案数, 我们先求交集为S的方案数,记为dp[S],发现处理起来还是比较麻烦, 我们放缩一下条件,求出交集包含S的方案数,记为dp[S], 我们发现dp[S],是以其为子集的方案的高维前缀和, 我们逆序求高维前缀和即可,之后考虑容斥,求出交集为0的情况, 我们发现这个容斥

codeforces 938F(dp+高维前缀和)

题意: 给一个长度为n的字符串,定义$k=\floor{log_2 n}$ 一共k轮操作,第i次操作要删除当前字符串恰好长度为$2^{i-1}$的子串 问最后剩余的字符串字典序最小是多少? 分析: 首先很容易得到一个性质,那就是删除的那些串是可以不交叉的 很容易想到一个很简单的dp dp[i][j]表示考虑原串的前i位,删除状态为j的情况下字典序最小的字符串(注意dp里面保存的是个字符串) 那么很明显就是个O(n^3logn)的dp,无法通过 dp里是一个字符串这个东西是很浪费时间而且很不优美的