并不对劲的复健训练-p3674

题目大意

给出序列$ a_1,...,a_n $ ( $ n\leq10^5,a\leq 10^5 $ ),有\(m\) ( \(m\leq 10^5\))个以下三类询问:

(1)给出\(l,r,k\)(\(k\leq 10^5\)),问是否存在\(x,y\)使\(x\in[l,r],y\in[l,r],a_x-a_y=k\)
(2)给出\(l,r,k\)(\(k\leq 10^5\)),问是否存在\(x,y\)使\(x\in[l,r],y\in[l,r],a_x+a_y=k\)
(3)给出\(l,r,k\)(\(k\leq 10^5\)),问是否存在\(x,y\)使\(x\in[l,r],y\in[l,r],a_x\times a_y=k\)

题解

发现\(a、k\)的值域较小,而且没有修改或强制在线,考虑莫队。
维护表示每个值在当前区间中是否存在的bitset,记为\(c\)。
对于(1)操作,将式子变形为\(a_x=a_y+k\),判断\((c<<k)| c\)中第\(k\)位是否为1
对于(2)操作,将式子变形为\(a_x=k-a_y\),发现\(-a_y\)不好直接算,但是可以维护\((10^5-a_y)\),使式子变为\(a_x=(10^5-a_y)-10^5+k\),记\((10^5-a_y)\)为\(d\),判断\((d>>(10^5-k))|c\)中第\(k\)位是否为1
对于(3)操作,难以变形,可以考虑把\(k\)拆成\(\sqrt k\)个约数,判断\(\sqrt k\)个约数中是否有存在于\(a_l,...,a_r\)的。这样听上去是 莫队的时间复杂度\(\times \sqrt k=n^2\)级别的。但是发现这么写的代码长这样:

rep i 1 to m
    移动左右端点;
    判断根号k个约数;

所以判断约数的 \(\sqrt k\)和莫队的\(\sqrt n\)是相加的关系。

代码
#include<algorithm>
#include<bitset>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];k!=-1;k=nxt[k])
#define maxn 100007
#define maxk 100000
#define LL long long
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*f;
}
void write(int x)
{
    if(x==0){putchar('0'),putchar('\n');return;}
    int f=0;char ch[20];
    if(x<0)putchar('-'),x=-x;
    while(x)ch[++f]=x%10+'0',x/=10;
    while(f)putchar(ch[f--]);
    putchar('\n');
    return;
}
bitset<100001>now,pnow;
int a[maxn],n,m,num[maxn],ans[maxn],blo=300;
struct quest{int f,l,r,x,id;}q[maxn];
bool cmp(quest x,quest y){return (x.l/blo==y.l/blo)?(x.r<y.r):(x.l<y.l);}
void add(int id,int f)
{
    num[a[id]]+=f;
    if(f==1&&num[a[id]]==1){now[a[id]]=1,pnow[maxk-a[id]]=1;}
    if(f==-1&&!num[a[id]]){now[a[id]]=0,pnow[maxk-a[id]]=0;}
}
int main()
{
    n=read(),m=read();
    rep(i,1,n)a[i]=read();
    rep(i,1,m)q[i].f=read(),q[i].l=read(),q[i].r=read(),q[i].x=read(),q[i].id=i;
    int nowl=1,nowr=1;num[a[1]]=1,now[a[1]]=1,pnow[maxk-a[1]]=1;
    sort(q+1,q+m+1,cmp);
    rep(i,1,m)
    {
        while(nowl<q[i].l){add(nowl,-1),nowl++;}
        while(nowr>q[i].r){add(nowr,-1),nowr--;}
        while(nowl>q[i].l){nowl--,add(nowl,1);}
        while(nowr<q[i].r){nowr++,add(nowr,1);}
        if(q[i].f==1){if(((now<<q[i].x)&now).any())ans[q[i].id]=1;}
        else if(q[i].f==2){if(((pnow>>(maxk-q[i].x))&now).any())ans[q[i].id]=1;}
        else
        {
            int lim=sqrt(q[i].x);
            rep(j,1,lim)if(q[i].x%j==0&&now.test(j)&&now.test(q[i].x/j)){ans[q[i].id]=1;break;}
        }
    }
    rep(i,1,m)puts(ans[i]?"hana":"bi");
    return 0;
}
一些感想

之前轻视bitset的人被bitset教做人了
bitset常用操作:

#include<bitset>//bitset的头文件
bitset<6342>a; //开一个下标从0~6341的bitset
a[63]=1,a[42]=0,a.set(63,1),a.set(42,0),a.reset(42);//赋值
a.set(),a.reset();//全变成1或全变成0
((a<<634)|(a>>23)).any();//bitset可以直接进行位运算,any()返回是否存在一位是1
a.none(),a.all(),a.test(5);//是否任意一位都为0;是否任意一位都为1;是否第5位为1
a.flip(32),a[32].flip();//翻转第32位
a.flip();//翻转全部
a.count(),a.size();//返回一共有几位是1;返回一共有几位
a.to_string(),a.to_ulong(),a.to_ullong();//把bitset变成string;unsigned long;unsigned long long

原文地址:https://www.cnblogs.com/xzyf/p/11532017.html

时间: 2024-08-07 14:32:50

并不对劲的复健训练-p3674的相关文章

并不对劲的复健训练-bzoj5253:loj2479:p4384:[2018多省联考]制胡窜

题目大意 给出一个字符串\(S\),长度为\(n\)(\(n\leq 10^5\)),\(S[l:r]\)表示\(S_l,S_{l+1}...,S_r\)这个子串.有\(m\)(\(m\leq 3\times 10^5\))次询问,每次询问给出\(l,r\),问有多少对\((i,j)\)(\(1\leq i<i+1<j\leq n\)),使与\(S[l:r]\)本质相同的子串出现在\(S[1:i]\)中或\(S[i+1:j-1]\)中或\(S[j:n]\)中. 题解 询问相当于是问有多少种方案

并不对劲的复健训练-CF1187D

题目大意 有两个长度为\(n\)的序列\(a_1,...,a_n\),\(b_1,...,b_n\)($a,b\leq n\leq 3\times 10^5 \().一次操作是选取\)[l,r]\(,将\)a_l,...,a_r$排序.问能否通过若干次操作把 \(a_1,...,a_n\) 变得和 \(b_1,...,b_n\) 一样. 题解 首先,如果\(a,b\)中每个数的出现次数不一样,那么一定不能. 其余的部分的问题在于能不能通过交换\(a\)中一些数的位置使\(a\)变得和\(b\)一

[全是废话的日记]离梦醒还有82天,中老年退役选手复健之路

帮兴dalao劝小学妹,顺便收获了一波嘲讽,比如一个人闷头做题 我是真的不适合这种劝人的活啊,我只会开嘲讽怼回去 然后发现辣鸡兴大佬,天天就知道骂人家妹子,骂完了,妹子玻璃心,又开始疯狂找人劝,你当初别骂那么狠啊! 我现在心态爆炸了,我也想有学长劝. 好了,吐槽时间结束,开始伟大的复健之路,又称咸鱼不忍心白白死去的垂死挣扎. (不要相信这句话,我真的全篇都在吐槽一点干货都没留) 你们能相信我打一个动态规划,从19号22点,打到现在20号快1点还没打完吗. 真是复健之路艰辛啊,明天(实际上应该是今

复健计划

这里就是复健计划啦!虽然实际上我只是把以前的归档复制了一遍而已啦,当然我加了一些基础的东西在里面就是了. 计划打算在七月初开始(只要不咕). 感觉是在水博客啊……没事,应该没人看(滑稽) 学完的后面打个√. 图论 建图方法 最短路 生成树 拓扑排序 Tarjan相关 2-SAT 欧拉回路 虚树 圆方树 网络流/匈牙利算法 KM 最大流最小割 费用流 二分图匹配 上下界网络流 —————————————————————— 数论 筛法 gcd/exgcd 逆元 康托展开,卡特兰数,斯特林数 卢卡斯定

【读书笔记/复健向】算法竞赛入门经典训练指南1.1贪心部分

例题一(UVa11292) 基础贪心,没什么需要多讲的,直接放上代码.有一点要注意的是我第一遍写的时候竟然犯了两个错误. 错误点 将dragon.knight与i.j对应错误了,仔细一想人有先后对应的天性,下次设置i.j时还是老老实实根据输入顺序来,避免出错 第23行遗漏了(j<n)这个条件,使得在龙已经全被砍头的情况下却雇佣了剩余的骑士. 本题重点 砍龙头的时候设置两个指针,分别移动,使用频率挺高的一个小技巧,不难,但是挺重要的. 1 #include<iostream> 2 #inc

下你现场v那下次v成功的复健科

 http://www.djkk.com/blog/xzqjtw05 http://www.djkk.com/blog/mysong-4439957.html http://www.djkk.com/blog/mydiarry-4439957.html http://www.djkk.com/blog/myfav-4439957.html http://www.djkk.com/blog/zjmore-4439957.html http://www.djkk.com/blog/mypic-4

【读书笔记/解题报告/复健向】动态规划

<挑战程序设计竞赛>2.3.1(POJ3624/NOIP2004采药问题) 最基础的01背包问题,标程性质,又二维和一维两种写法. 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 using namespace std; 6 const int MAXN=3403; 7 int w[MAXN]; 8 int v[MAXN]; 9 int

复健小CM

系统 : Windows xp 程序 : Keygenme # 2 程序下载地址 :http://pan.baidu.com/s/1qYIk2HQ 要求 : 注册机编写 使用工具 : OD 可在“PEDIY CrackMe 2007”中查找关于此程序的讨论,标题为“一个据说是新手级Crackme的分析”. 运行程序,查找字符串定位关键算法位置.大致的看一下程序主体: 004014AF |. C74424 04 CE0>mov dword ptr [esp+4], 004400CE ; enter

噢耶肉体上的分就该的加萨克的恢复四复健科

http://f.dangdang.com/group/24297/953021/ http://f.dangdang.com/group/24297/953022/ http://f.dangdang.com/group/24297/953023/ http://f.dangdang.com/group/24297/953024/ http://f.dangdang.com/group/24297/953025/ http://f.dangdang.com/group/24297/953026