zoukankan      html  css  js  c++  java
  • 洛谷 P5527

    洛谷题面传送门

    一道挺有意思的题,想到了某一步就很简单,想不到就很毒瘤(

    首先看到这样的设问我们显然可以想到背包,具体来说题目等价于对于每个满足 (iin[l,r])(a_i) 赋上一个权值 (v_iin{-1,0,1}),满足 (sumlimits_{i=l}^rv_ia_i=0),这是显然可以 (01) 背包求解的,时间复杂度 (qnv),一脸过不去的亚子,可以使用 bitset 优化到 (dfrac{qnv}{omega}),但没啥卵用,还是过不去。

    这时候我们就要发现一个非常强的性质了。首先比较显然的一点是这个交集为空用处不大,只要不是两个集合重合就行,因为如果交集非空那把交集的部分从两个集合中扣掉和依然是相同的。注意到对于一段区间而言,我们只用判断是否存在两个集合和相同,而对于这个区间的所有子集,它们总共可能贡献出 (2^{r-l+1}) 个子集,而和最大只有 ((r-l+1)·v),因此如果区间长度 (len) 满足 (len·v<2^{len}),即 (lenge 14),那根据抽屉原理就必然存在两个集合和相同,答案也就是 Yuno 了。

    有了这个性质之后事情就变得容易许多。由于 (lenge 14)​ 的情况已经给判掉了,我们只用判断 (lenle 13)​ 的情况即可,这个就按照上面的套路 bitset 优化背包即可,甚至实测折半搜 (q·3^7) 都可以通过。还有一个小问题是怎样处理修改操作,我们开一棵 BIT 维护每个元素被执行了多少次 (a_ileftarrow a_i^3) 这样的操作,假设这个值为 (c),那么显然执行完 (c) 次操作后会有 (a_i=a_i^{3^c}),一个很直观的想法是扩展欧拉定理降幂,不过由于此题权值很小,可以考虑倍增。具体来说设 (cub_{i,j}=i^{3^{2^j}})​,那么显然有 (i^{3^{2^j}}=(i^{3^{2^{j-1}}})^{3^{2^{j-1}}}),倍增一下即可。

    时间复杂度 (nlog n+dfrac{13qv}{omega})

    const int MAXN=1e5;
    const int MAXV=1000;
    const int DLT=14002;
    const int LOG_N=17;
    int n,qu,p,cub[MAXV+5][LOG_N+2],t[MAXN+5],a[MAXN+5];
    void add(int x,int v){for(int i=x;i<=n;i+=(i&(-i))) t[i]+=v;}
    void add_range(int l,int r,int v){add(l,v);add(r+1,-v);}
    int query(int x){int ret=0;for(int i=x;i;i&=(i-1)) ret+=t[i];return ret;}
    int ask(int x){
    	int cnt=query(x),cur=a[x];
    	for(int i=LOG_N;~i;i--) if(cnt>>i&1) cur=cub[cur][i];
    	return cur;
    }
    bitset<DLT*2+5> bs;
    int main(){
    	scanf("%d%d%d",&n,&qu,&p);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for(int i=0;i<p;i++) cub[i][0]=i*i*i%p;
    	for(int i=1;i<=LOG_N;i++) for(int j=0;j<p;j++)
    		cub[j][i]=cub[cub[j][i-1]][i-1];
    	while(qu--){
    		int opt,l,r;scanf("%d%d%d",&opt,&l,&r);
    		if(opt==1){
    			if(r-l+1>14) puts("Yuno");
    			else{
    				bs.reset();
    				for(int i=l;i<=r;i++){
    					int v=ask(i)+1;
    					bs=bs|(bs<<v)|(bs>>v);
    					bs.set(DLT+v);bs.set(DLT-v);
    				} printf("%s
    ",(bs.test(DLT)?"Yuno":"Yuki"));
    			}
    		} else add_range(l,r,1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Servlet的几种跳转(转)
    Java String.split()用法小结(转)
    表单数据提交的方法
    gedit文本编辑器乱码解决办法
    J-Link烧写bootloader到mini2440的Nor Flash
    虚拟机安装Fedora10系统遇到异常
    linux系统忘记root密码怎么办?
    编译busybox时出错及解决方案
    source insight代码查看器如何自定义添加文件类型
    < Objective-C >文件操作-NSFileHandle
  • 原文地址:https://www.cnblogs.com/ET2006/p/luogu-P5527.html
Copyright © 2011-2022 走看看