题解 english
好题 肝完这题感觉头巨痛
首先\(n \leqslant 1000\)的部分可以\(n^2\)单调队列,有30pts
然后考场上魔改了下单调栈,让它能顺便维护出以\(1~i-1\)为左端点的区间信息,又拿下op=1的30pts
其实这里第11、12个点的答案必定为0,但是没意识到
至于正解:
其实第一问就跑上面魔改单调栈解法就行,是基于这个性质:
- \((a\oplus b)*k = \sum\limits_{i=0}^{30} (a\oplus b)*2^i*k\)
然后就可以按位拆开求解了
然后第二问利用可持久化trie树实现了查询区间内大于某个数的个数
「模板」可持久化trie树查询区间内大于某个数的个数:
int n, m;
int tot, rot[N], son[N][2], cnt[N];
#define son(a, b) son[a][b]
#define cnt(a) cnt[a]
void ins(int u, int p1, int p2, int dat) {
if (u<0) return ;
int s=bool((1<<u)&dat);
son(p2, s)=++tot;
cnt(son(p2, s))=cnt(son(p1, s))+1;
son(p2, s^1)=son(p1, s^1);
ins(u-1, son(p1, s), son(p2, s), dat);
}
int query(int u, int p1, int p2, int dat) {
//cout<<"query "<<u<<endl;
if (u<0) return 0;
int s=bool((1<<u)&dat), ans=0;
if (!s) ans=query(u-1, son(p1, 0), son(p2, 0), dat)+cnt(son(p2, 1))-cnt(son(p1, 1));
else ans=query(u-1, son(p1, 1), son(p2, 1), dat);
return ans;
}
signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
n=read(); m=read();
for (int i=1; i<=n; ++i) rot[i]=++tot, ins(25, rot[i-1], rot[i], read());
for (int i=1,a,b,c,d; i<=m; ++i) {
a=read(); b=read(); c=read();
cout<<query(25, rot[a-1], rot[b], c)<<endl;
}
return 0;
}
但是这题要求区间内数先异或上一个数,再比较大小
其实稍稍改下query函数即可
int n, m;
int tot, rot[N], son[N][2], cnt[N];
#define son(a, b) son[a][b]
#define cnt(a) cnt[a]
void ins(int u, int p1, int p2, int dat) {
if (u<0) return ;
int s=bool((1<<u)&dat);
son(p2, s)=++tot;
cnt(son(p2, s))=cnt(son(p1, s))+1;
son(p2, s^1)=son(p1, s^1);
ins(u-1, son(p1, s), son(p2, s), dat);
}
int query(int u, int p1, int p2, int dat, int dlt) {
//cout<<"query "<<u<<endl;
if (u<0) return 0;
int s=bool((1<<u)&dat), s2=bool((1<<u)&dlt), ans=0;
if (!s2) {
if (!s) ans=query(u-1, son(p1, 0), son(p2, 0), dat, dlt)+cnt(son(p2, 1))-cnt(son(p1, 1));
else ans=query(u-1, son(p1, 1), son(p2, 1), dat, dlt);
return ans;
}
else {
if (!s) ans=query(u-1, son(p1, 1), son(p2, 1), dat, dlt)+cnt(son(p2, 0))-cnt(son(p1, 0));
else ans=query(u-1, son(p1, 0), son(p2, 0), dat, dlt);
return ans;
}
}
signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
n=read(); m=read();
for (int i=1; i<=n; ++i) rot[i]=++tot, ins(25, rot[i-1], rot[i], read());
for (int i=1,a,b,c,d; i<=m; ++i) {
a=read(); b=read(); c=read(); d=read();
cout<<query(25, rot[a-1], rot[b], c, d)<<endl;
}
return 0;
}
那有了这个东西,我们考虑原题
要求区间端点异或值大于区间内最大值
那可以分别预处理出每个值所“管辖“的区间,单调栈扫两遍即可,这样不枚举端点而是枚举最大值的话就可以少个\(O(n)\)
有个神仙转化:
每个值所“管辖“的区间至多相互包含,但不能相交
这跟线段树的结构相似,所以区间总长度至多为nlogn
对于每个区间,直接暴力枚举左右区间中较小的一个
树链剖分的折半思想可知,至多枚举log次,枚举的总长度为区间总长度
所以时间复杂度\(O(nlog^2n)\)
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, op;
const ll p=1e9+7;
ll a[N], ans1, ans2;
namespace force{
struct que{ll val; int pos; inline void build(ll v_, int p_){val=v_; pos=p_;}}q[N];
void solve() {
ll t;
for (int len=2,l,r; len<=n; ++len) {
l=1; r=0;
for (int i=1; i<=len; ++i) {
while (l<=r && a[i]>=q[r].val) --r;
q[++r].build(a[i], i);
}
for (int i=len,l2; i<=n; ++i) {
l2=i-len+1;
t=a[l2]^a[i];
while (l<=r && q[l].pos<l2) ++l;
while (l<=r && a[i]>=q[r].val) --r;
q[++r].build(a[i], i);
//cout<<"+= "<<t*q[l].val<<endl;
ans1 = (ans1+t*q[l].val)%p;
ans2 = (ans2+((t>q[l].val)?q[l].val:0))%p;
}
}
if (op==1) printf("%lld\n", ans1%p);
else if (op==2) printf("%lld\n", ans2%p);
else printf("%lld\n%lld\n", ans1%p, ans2%p);
exit(0);
}
}
namespace task1{
struct que2{
struct que{ll val, cnt, sum; inline void build(ll v_, ll p_, ll s_){val=v_; cnt=p_; sum=s_;}}q[N];
int l, r;
que2():l(1),r(0){}
void upd(ll w) {
if (l>r || w<q[r].val) return ;
ll cnt=0;
while (l<=r && w>=q[r].val) cnt+=q[r--].cnt;
ll s=(l<=r)?q[r].sum:0;
q[++r].build(w, cnt, (s+w*(cnt)%p)%p);
}
void add(ll w) {
ll cnt=0;
while (l<=r && w>=q[r].val) cnt+=q[r--].cnt;
ll s=(l<=r)?q[r].sum:0;
q[++r].build(w, cnt+1, (s+w*(cnt+1)%p)%p);
}
ll ask(ll w) {return l<=r?q[r].sum:0;}
}que[22][2];
void solve() {
for (int i=1; i<=n; ++i) {
for (int j=0; j<22; ++j) {
int s=(a[i]&(1<<j))?1:0;
que[j][s^1].upd(a[i]);
ans1=(ans1+(que[j][s^1].ask(a[i]))*(1<<j)%p)%p;
que[j][s].add(a[i]);
}
}
printf("%lld\n", ans1%p);
}
}
namespace task2{
int l[N], r[N];
struct que{ll val; int pos; inline void build(ll v_, int p_){val=v_; pos=p_;}}q[N];
int ql, qr;
const int SIZE=N*50;
int tot, rot[N], son[SIZE][2], cnt[SIZE];
#define son(a, b) son[a][b]
#define cnt(a) cnt[a]
void ins(int u, int p1, int p2, int dat) {
if (u<0) return ;
int s=bool((1<<u)&dat);
son(p2, s)=++tot;
cnt(son(p2, s))=cnt(son(p1, s))+1;
son(p2, s^1)=son(p1, s^1);
ins(u-1, son(p1, s), son(p2, s), dat);
//if (u>1) pushup(p2);
}
int query(int u, int p1, int p2, int dat, int dlt) {
//cout<<"query "<<u<<endl;
if (u<0) return 0;
int s=bool((1<<u)&dat), s2=bool((1<<u)&dlt), ans=0;
if (!s2) {
if (!s) ans=query(u-1, son(p1, 0), son(p2, 0), dat, dlt)+cnt(son(p2, 1))-cnt(son(p1, 1));
else ans=query(u-1, son(p1, 1), son(p2, 1), dat, dlt);
return ans;
}
else {
if (!s) ans=query(u-1, son(p1, 1), son(p2, 1), dat, dlt)+cnt(son(p2, 0))-cnt(son(p1, 0));
else ans=query(u-1, son(p1, 0), son(p2, 0), dat, dlt);
return ans;
}
}
void solve() {
ql=qr=1; q[1].build(INF, 0);
for (int i=1; i<=n; ++i) {
while (ql<=qr && q[qr].val<a[i]) --qr;
l[i]=q[qr].pos+1;
q[++qr].build(a[i], i);
}
ql=qr=1; q[1].build(INF, n+1);
for (int i=n; i; --i) {
while (ql<=qr && q[qr].val<=a[i]) --qr;
r[i]=q[qr].pos-1;
q[++qr].build(a[i], i);
}
//cout<<"l: "; for (int i=1; i<=n; ++i) cout<<l[i]<<' '; cout<<endl;
//cout<<"r: "; for (int i=1; i<=n; ++i) cout<<r[i]<<' '; cout<<endl;
for (int i=1; i<=n; ++i) rot[i]=++tot, ins(21, rot[i-1], rot[i], a[i]);
for (int i=1; i<=n; ++i) {
if (l[i]==r[i]) continue;
if (i-l[i]<r[i]-i) for (int j=l[i]; j<=i; ++j) ans2=(ans2+a[i]*query(21, rot[i-1], rot[r[i]], a[i], a[j])%p)%p; //, cout<<"query "<<i<<' '<<r[i]<<' '<<j<<endl;
else for (int j=i; j<=r[i]; ++j) ans2=(ans2+a[i]*query(21, rot[l[i]-1], rot[i], a[i], a[j])%p)%p; //, cout<<"query "<<l[i]<<' '<<i<<' '<<j<<endl;
}
printf("%lld\n", ans2%p);
}
}
signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
n=read(); op=read();
for (int i=1; i<=n; ++i) a[i]=read();
if (op==1||op==3) task1::solve();
if (op==2||op==3) task2::solve();
return 0;
}
题解 english的更多相关文章
- Java - 收藏集 -
Java - 收藏集 - Java 基础思维导图,让 Java 不再难懂 - 工具资源 - 掘金思维导图的好处 最近看了一些文章的思维导图,发现思维导图真是个强大的工具.了解了思维导图的作用之后, ...
- LeetCode Integer to English Words
原题链接在这里:https://leetcode.com/problems/integer-to-english-words/ Convert a non-negative integer to it ...
- 273. Integer to English Words
题目: Convert a non-negative integer to its english words representation. Given input is guaranteed to ...
- 【Codeforces Round】 #431 (Div. 2) 题解
Codeforces Round #431 (Div. 2) A. Odds and Ends time limit per test 1 second memory limit per test ...
- Codeforces Round #447 (Div. 2) 题解 【ABCDE】
BC都被hack的人生,痛苦. 下面是题解的表演时间: A. QAQ "QAQ" is a word to denote an expression of crying. Imag ...
- LeetCode All in One题解汇总(持续更新中...)
突然很想刷刷题,LeetCode是一个不错的选择,忽略了输入输出,更好的突出了算法,省去了不少时间. dalao们发现了任何错误,或是代码无法通过,或是有更好的解法,或是有任何疑问和建议的话,可以在对 ...
- Codeforces Round #177 (Div. 2) 题解
[前言]咦?如今怎么流行打CF了?于是当一帮大爷在执着的打div 1的时候,我偷偷的在刷div 2.至于怎么决定场次嘛.一般我报一个数字A,随便再拉一个人选一个数字B.然后開始做第A^B场.假设认为机 ...
- 【字符串】【hash】【倍增】洛谷 P3502 [POI2010]CHO-Hamsters 题解
这是一道字符串建模+图论的问题. 题目描述 Byteasar breeds hamsters. Each hamster has a unique name, consisting of lo ...
- Codeforces Round #470 Div. 2题解
A. Protect Sheep time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
随机推荐
- 第三章 深入理解python语言
计算机技术的演进过程 1946-1981年 计算机系统结构时代(35年) 解决计算机能力的问题 1981-2008年 网络和视窗时代(27年) 解决交互问题 2008-2016年 复杂信息系统时代(8 ...
- 理解Python中的闭包
1.定义 闭包是函数式编程的一个重要的语法结构,函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式).在面向过程编程中,我们见到过函数(function):在面向对象编程中,我们见 ...
- 知识全聚集 .Net Core 技术突破 丨ABP vNext 开始
介绍 很久没有更新博客了,之前想更新但是发现博客园崩了,外加工作上的调换也比较忙,最近有了点时间我来继续更新下这个系列的文章. 今年3月份我带着我们研发组同事,将公司产品从老Abp重构到Abp vNe ...
- Spring Boot(一):如何使用Spring Boot搭建一个Web应用
Spring Boot Spring Boot 是Spring团队旗下的一款Web 应用框架 其优势可以更快速的搭建一个Web应用 从根本上上来讲 Spring Boot并不是什么新的框架技术 而是在 ...
- React事件绑定的方式
一.是什么 在react应用中,事件名都是用小驼峰格式进行书写,例如onclick要改写成onClick 最简单的事件绑定如下: class ShowAlert extends React.Compo ...
- 【LeetCode】61. 旋转链表
61. 旋转链表 知识点:链表: 题目描述 给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置. 示例 输入:head = [1,2,3,4,5], k = 2 输出:[4 ...
- 前端基础div(六)
实例 文档中的一个部分会显示为绿色: <div style="color:#00FF00"> <h3>This is a header</h3> ...
- linux删除命令
Linux下的命令,删除文件夹下的所有文件,而不删除文件夹本身rm -rf *
- php header 设置文件下载
控制器 php 代码: $filepath = "http://www.jiesen365.com/uploadfile/20150519044903-897.pdf"; //下载 ...
- 《手把手教你》系列技巧篇(十四)-java+ selenium自动化测试-元素定位大法之By xpath上卷(详细教程)
1.简介 按宏哥计划,本文继续介绍WebDriver关于元素定位大法,这篇介绍定位倒数二个方法:By xpath.xpath 的定位方法, 非常强大. 使用这种方法几乎可以定位到页面上的任意元素. ...