奇怪的姿势?高维前缀和

奇怪的姿势:高维前缀和

首先请先看一题:

Bzoj5092:

一句话题面:
我们做xor前缀和后,对每一个i,输出j<i,max(s[i]^s[j]+s[j])。

一般人估计上来就想可持久化Trie了。
然而我们发现,对于某一位,如果s[i]这位为1,对于s[j],这位如果是0的话贡献为1,是1的话贡献为0。
but,如果s[i]这位为0,那么对于s[j],这位如果是0的话贡献为0,是1的话贡献为2。
等等,这怎么还带进位的?这玩意能做?

可持久化Trie当然是做不了的,于是我们需要一种叫做高维前缀和的东西。
考虑我们如果把i的二进制表示看做一个集合(状态压缩总会吧),我们要统计i的超集的一些信息。
说人话,就是对于i,我们要满足统计(j&i)==i的j的一些信息。
这就是高维前缀和所做的事情了。
如何统计?
我们先从低到高满足j和i存在差异的第一个位置,然后对不包含这个位置的i补全这个位置,并统计答案。
也就是:
if( ! ( i & ( 1 << b ) ) ) f[i] = f[i] add f[i|(1<<b)]
这里的add可以是任何满足加和性质的运算,比如+,^,min(),max(),等等。
考虑这样做为什么是对的,首先和i在更低位置有差异的已经被统计了(废话,看你前面位数怎么循环的)。
然后考虑此时的f[j](这里j=i|(1<<b)),他包含了和j在更低位置存在差异的数值的信息。
也就是说,我们在把f[j]的信息加入f[i]的同时,同时加入了和i在这一位有差异且在更低位有差异的所有值的信息。
所以这个东西不会漏算。
为什么不会算重?因为我们统计的时候每次的最高差异位是不同的!

考虑如何用这个东西来完成Bzoj5092。
我们令f[k]表示二进制表示包含k的最靠前位置。
然后我们从高到低贪心枚举位数。
如果s[i]的当前位为1,我们对于s[j]此位选择0和1都相同,我们可以忽略这位。
如果s[i]当前位为0,我们就要贪心选择s[j]当前位为1的j。
假设我们已经选出的状态为cur。如果我们能够找到这样的j的话,需要满足的条件是:f[cur^(1<<b)]<=i。
去判定一下就可以了。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 const int maxn=3e5+1e2,maxm=4e6+1e2,lim=2097152;
 5 
 6 int in[maxn],f[maxm];
 7 
 8 inline void pre() {
 9     for(int b=0;b<=20;b++)
10         for(int i=0;i<lim;i++)
11             if( ! ( i & ( 1 << b ) ) ) f[i] = std::min( f[i] , f[i|(1<<b)] );
12 }
13 
14 int main() {
15     static int n;
16     scanf("%d",&n) , memset(f,0x3f,sizeof(f));
17     for(int i=1;i<=n;i++) {
18         scanf("%d",in+i) , 
19         in[i] ^= in[i-1] , 
20         f[in[i]] = std::min( f[in[i]] , i );
21     }
22     pre();
23     for(int i=1,cur;i<=n;i++) {
24         cur = 0;
25         for(int b=20;~b;b--) if( ! ( in[i] & ( 1 << b ) ) ) {
26             if( f[cur|(1<<b)] <= i ) cur |= ( 1 << b );
27         }
28         printf("%d\n",(in[i]^cur)+cur);
29     }
30     return 0;
31 }
View Code

 



其实关于高维前缀和还有一道更经典的题目:
SPOJ TLE:

网上抄的中文题面:
给出n个数字c,求非负整数序列a,满足a<2^m。
并且有a[i]&a[i+1]=0,对于每个a[i],要保证a[i]不是c[i]的倍数。
求这样的a[i]序列的个数。

我们考虑DP,设f[i][j]表示前i位最后一位为j的方案数。
我们枚举下一位选择的数,假设为x,这样我们需要满足a[i+1]%c[i+1]!=0。
且对于第i位选择的数,j & x == 0。
这是什么意思呢?考虑我们对x的二进制表示求补集为w, j需要为w的子集。
高维前缀和也能统计子集信息,只要我们修改一下转移条件和转移来源就好了。
if( i & ( 1 << b ) ) f[i] += f[i^(1<<b)]。
就是把这一个差异位去掉啦。
什么,你说枚举子集,我们也能够用一个for循环实现?
for(int ss=s;ss;ss=s&(ss-1))
但是这不能原地址运算吧,而高维前缀和可以(可能在统计子集上也就这点优势了)。
然而统计超集,你告诉我一个for循环怎么做?这才是高维前缀和发挥作用的地方。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 const int maxn=55,maxe=32873;
 4 const int mod=1000000000;
 5 
 6 int f[maxn][maxe],sum[maxe],ans;
 7 int c[maxn];
 8 int n,m,lim,neg;
 9 
10 inline void rebuild(int* sou) {
11     memcpy(sum,sou,sizeof(sum));
12     for(int i=0;i<m;i++)
13         for(int j=0;j<lim;j++)
14             if( ( j & ( 1 << i ) ) )
15                 sum[j] = ( sum[j] + sum[j^(1<<i)] ) % mod;
16 }
17 inline void trans(int* f,int c) {
18     for(int i=0;i<lim;i++)
19         if( i % c )
20             f[i] = ( f[i] + sum[neg^i] ) % mod;
21 }
22 
23 int main() {
24     static int T;
25     scanf("%d",&T);
26     while(T--) {
27         memset(f,0,sizeof(f)) , ans = 0;
28         scanf("%d%d",&n,&m) , lim = 1 << m , neg = lim - 1;
29         for(int i=1;i<=n;i++) scanf("%d",c+i);
30         for(int i=0;i<lim;i++) if( i % c[1] ) f[1][i] = 1;
31         for(int i=2;i<=n;i++) rebuild(f[i-1]) , trans(f[i],c[i]);
32         for(int i=0;i<lim;i++) ans = ( ans + f[n][i] ) % mod;
33         printf("%d\n",ans);
34     }
35     return 0;
36 }
View Code



PS:话说作为一个高二省选选手,以前竟然连这东西都不会,我果然还是太菜了啊。
我不够努力;我不够强;我还能做得更好,然而我没有;我是错误的;我在犯罪;我该死。

转载于:https://www.cnblogs.com/Cmd2001/p/8519387.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值