DTOJ#5193. 来硬的

传送门

题目背景

又是一个无聊的下午,Wu_Mr108oahnew 都有些不知道想干什么。

“想不想来点刺激的?”Wu_Mr108oahnew 询问。

“啥?这可是在机房,能搞啥?”

Wu_Mr 露出不怀好意地微笑。“就是机房才刺激嘛。”

说着,她就从自己的凳子上站起来,坐到了 108oahnew 的腿上。108oahnew 的脸瞬间涨红了。

“喂,快下来,被教练看到就凉凉了。”

“别啊,这多有意思。”说着,Wu_Mr 就把脸向 108oahnew 的脸凑了过去。

“李在赣神魔?快坐回到自己的座位上去。”来自一只从门口进来的教练。

Wu_Mr 意犹未尽地坐了回去。

因为教练觉得 Wu_Mr 的行为太不好了,于是就罚 Wu_Mr 去做了一道比较难的题。

但是 Wu_Mr 毕竟是神,那种题对她来说太简单了。不过本着有福同享的原则,她把题改简单了一些给了 108oahnew 来做。

题面描述

给定一个长度为 n n n 的数列 ,有 q q q 次询问,每次给定三个数 l , r , w l,r,w l,r,w,你要求出 ∑ i = l r ⌊ w a i ⌋ \sum_{i=l}^r \left\lfloor\dfrac{w}{a_i}\right\rfloor i=lraiw 的值。

部分测试点强制在线。
第一行四个数 n , q , t y p , W n,q,typ,W n,q,typ,W n n n q q q 含义如题面描述, t y p typ typ 表示是否强制在线( 0 0 0 表示不是, 1 1 1 表示是), W W W 的含义如下面描述。

接下来一行 n n n 个数,第 i i i 个数表示 a i a_i ai

接下来 q q q 行,每行三个数 l ′ , r ′ , w ′ l',r',w' l,r,w

如果 t y p = 0 typ=0 typ=0,则真实询问的 l = l ′ , r = r ′ , w = w ′ l=l',r=r',w=w' l=l,r=r,w=w

否则,真实询问的 l , r , w l,r,w l,r,w 由如下公式计算(其中 ⊕ \oplus 是异或位运算):
l = min ⁡ ( ( l ′ ⊕ l a s t a n s )   m o d   n + 1 , ( r ′ ⊕ l a s t a n s )   m o d   n + 1 ) l=\min((l' \oplus lastans) \bmod n + 1,(r' \oplus lastans)\bmod n + 1) l=min((llastans)modn+1,(rlastans)modn+1)
r = max ⁡ ( ( l ′ ⊕ l a s t a n s )   m o d   n + 1 , ( r ′ ⊕ l a s t a n s )   m o d   n + 1 ) r=\max((l' \oplus lastans) \bmod n + 1,(r' \oplus lastans)\bmod n + 1) r=max((llastans)modn+1,(rlastans)modn+1)
w = ( w ′ ⊕ l a s t a n s )   m o d   W + 1 w=(w' \oplus lastans)\bmod W + 1 w=(wlastans)modW+1

其中 l a s t a n s lastans lastans 表示上次询问的答案(初始为 0 0 0)。

对于每个询问输出一行一个数,表示对应询问的答案。保证答案在 int 范围内(出题人懒)。

样例输入 1
10 5 0 100
17 95 5 55 61 9 62 17 25 75
4 6 1
4 10 57
8 10 51
6 8 8
3 8 67
样例输出 1
0
12
5
0
26
样例输入 2
10 5 1 100
1 3 3 1 1 9 10 9 9 9
2 10 5
6 10 57
2 4 7
2 10 12
1 10 83
样例输出 2
10
86
191
252
167
样例解释 2

真实的询问分别是:

1 3 6

1 3 52

3 5 82

2 10 80

4 7 76
对于 20 % 20 \% 20% 的数据, n ≤ 100 n \leq 100 n100

对于另外 10 % 10 \% 10% 的数据, n ≤ 2000 , W ≤ 5000 n \leq 2000,W \leq 5000 n2000,W5000

对于另外 30 % 30 \% 30% 的数据, t y p e = 0 type=0 type=0

对于 100 % 100 \% 100% 的数据, n ≤ 1 0 5 , q ≤ 1 0 5 , W ≤ 1 0 5 , 1 ≤ a i ≤ 1 0 9 n \leq 10^5,q \leq 10^5, W \leq 10^5, 1 \leq a_i \leq 10^9 n105,q105,W105,1ai109

主席树是假的。。
O ( n n l o g n ) = 6 e 8 O(n\sqrt nlogn)=6e8 O(nn logn)=6e8 却是假的,未能卡过去。。
题解:
我们考虑分块。
首先,发现 ⌊ w a i ⌋ \left\lfloor\dfrac{w}{a_i}\right\rfloor aiw很像整数分块,同时注意到若我们对 a [ i ] a[i] a[i] n \sqrt n n 分块:
小于 n \sqrt n n 的查询时前缀和算。
大于 n \sqrt n n 的预处理倍数,也是 n n n\sqrt n nn 。查询时也是分块查询,对 n n n 分块,支持区间查询。

#include<bits/stdc++.h>
#define N 100005
using namespace std;
inline char GET_CHAR ( void )
{
    static char buf[1<<23],*p1=buf,*p2=buf;
    return p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2) ? EOF : *p1++;
}
inline int read ( void )
{
	int x=0;char ch;
	while ( !isdigit(ch=GET_CHAR()) ) ;
	for ( x=ch^48;isdigit(ch=GET_CHAR()); ) x=(x<<1)+(x<<3)+(ch^48);
	return x;
}/*
int read(){
	int op=1,sum=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') op=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+ch-'0',ch=getchar();
	return op*sum;
}*/
int a[N],sq=320,cn[N][321],f[321][N];
int main(){
//	freopen("papapa7.in","r",stdin);
//	freopen("papapa.out","w",stdout);
	int n=read(),q=read(),typ=read(),W=read();
	//cout<<1<<endl;
	for(int i=1;i<=n;++i){
		a[i]=read();
		//for(int j=1;j<=sq;++j)cn[i][j]+=cn[i-1][j];
		/*if(a[i]<=sq){
			++cn[i][a[i]];
			continue;
		}*/
		for(int j=a[i];j<=W;j+=a[i])++f[(i-1)/sq+1][j];
	}
	for(int i=1;i<=(n-1)/sq+1;++i){
	    for(int j=1;j<=W;++j)f[i][j]+=f[i][j-1];
	    for(int j=1;j<=W;++j)f[i][j]+=f[i-1][j];
	}
	int ans=0;
	//cout<<1<<endl;
	while(q--){
		int l=read(),r=read(),w=read();
		if(typ){
			l=(l^ans)%n+1;r=(r^ans)%n+1;w=(w^ans)%W+1;
		    if(l>r)swap(l,r);
		}
		ans=0;
		//for(int i=1;i<=sq;++i)ans=ans+(w/i)*(cn[r][i]-cn[l-1][i]);
		//cout<<ans<<endl;
		int bl=(l-1)/sq+1,br=(r-1)/sq+1;
		if(bl<=br-1)ans+=f[br-1][w]-f[bl][w];
		for(int i=l;i<=min(bl*sq,r);++i)ans+=w/a[i];
		if(bl!=br)for(int i=max(l,(br-1)*sq+1);i<=r;++i)ans+=w/a[i];
		//ans>>=1;
		printf("%d\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值