bzoj 2506 calc 题解

【原题】

2506: calc

Time Limit: 10 Sec  Memory Limit: 256 MB

Submit: 228  Solved: 112

Description

给一个长度为n的非负整数序列A1,A2,…,An。现有m个询问,每次询问给出l,r,p,k,问满足l<=i<=r且Ai mod p = k的值i的个数。

Input

第一行两个正整数n和m。

第二行n个数,表示A1,A2,…,An。

以下m行,每行四个数分别表示l,r,p,k。满足1<=l<=r<=n。

Output

对于每个询问,输出一行,表示可行值i的个数。

Sample Input

5 2

1 5 2 3 7

1 3 2 1

2 5 3 0

Sample Output

2

1

HINT

数据范围:

0<n,m<=10^5,任意1<=i<=n满足Ai<=10^4,0<p<=10^4,0<=k<p。

【分析】初看题目我猜是神题,于是匆匆想去看题解。后来后悔自己没有仔细想!

解法是离线的,而且很巧妙。首先,把问题的首端点排序。对于P,我们分成两类:<=100和>100。

如果是<=100,随便暴力即可。我们设f[i][j]记录到目前这个点,除以i余j的个数,然后ans累加即可。

如果是>100,可以得到一个奇妙的性质:因为最大的数是10000,所以最多只有101个数满足除以P余K。那么对于某个询问,我们可以暴力枚举每个W使得W%P=K。然后把W个数累加即可。

【代码】

#include<cstdio>
#include<algorithm>
#define N 100005
#define O 105
using namespace std;
struct node{int x,p,k,g,id;}T[N*2],Q[N*2];
int data[N],ans[N],f[O][O],s[10005];
int n,m,i,j,L,R,K,P,t,q;
inline int Read()
{
  char ch=getchar();for (;ch<'0'||ch>'9';ch=getchar());
  int x=0;for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
  return x;
}
bool cmp(node a,node b){return a.x<b.x;}
void solve_small()
{
  sort(T+1,T+t+1,cmp);int k=1;
  while (k<=t&&!T[k].x) k++;
  for (int i=1;i<=n;i++)
  {
    for (int j=1;j<=100;j++)
      f[j][data[i]%j]++;
    while (k<=t&&T[k].x==i)
      ans[T[k].id]+=T[k].g*f[T[k].p][T[k].k],k++;
  }
}
void solve_big()
{
  sort(Q+1,Q+q+1,cmp);int k=1;
  while (k<=q&&!Q[k].x) k++;
  for (int i=1;i<=n;i++)
  {
    s[data[i]]++;
    while (k<=q&&Q[k].x==i)
    {
      int now=0;
      for (int j=Q[k].k;j<=10000;j+=Q[k].p) now+=s[j];
      ans[Q[k].id]+=Q[k].g*now;k++;
    }
  }
}
int main()
{
  scanf("%d%d",&n,&m);
  for (i=1;i<=n;i++) data[i]=Read();
  for (i=1;i<=m;i++)
  {
    L=Read();R=Read();P=Read();K=Read();
    if (P<=100) T[++t]=(node){L-1,P,K,-1,i},T[++t]=(node){R,P,K,1,i};
    else Q[++q]=(node){L-1,P,K,-1,i},Q[++q]=(node){R,P,K,1,i};
  }
  sort(Q+1,Q+m+1,cmp);
  solve_small();
  solve_big();
  for (i=1;i<=m;i++) printf("%d\n",ans[i]);
  return 0;
}

bzoj 2506 calc 题解

时间: 2024-08-29 14:31:59

bzoj 2506 calc 题解的相关文章

BZOJ 2506 calc

离线+权值分块.无法在线,每个节点存不下100*100. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100500 #define maxm 10500 using namespace std; struct query { int pos,id,val,a,b; }q[maxn*3]; int n,m,cnt[maxm],a[m

BZOJ 1179 Atm 题解

BZOJ 1179 Atm 题解 SPFA Algorithm Tarjan Algorithm Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口

函数式trie思想 &amp; Bzoj 3261 &amp; 3166 题解

[原题1] 3261: 最大异或和 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 497  Solved: 215 [Submit][Status] Description 给定一个非负整数序列 {a},初始长度为 N. 有   M个操作,有以下两种操作类型: 1 .A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1. 2 .Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得: a[p] xor a[

BZOJ 1008 越狱 题解 裸快速幂

BZOJ 1008 越狱 题解 裸快速幂 1008: [HNOI2008]越狱 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 7887  Solved: 3372[Submit][Status][Discuss] Description 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱 Input 输入两个整数M,N.1<=M<

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output 输出一个整数,

斜率优化专题3——bzoj 3156 防御准备 题解

[原题] 3156: 防御准备 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 198  Solved: 107 [Submit][Status] Description Input 第一行为一个整数N表示战线的总长度. 第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai. Output 共一个整数,表示最小的战线花费值. Sample Input 10 2 3 1 5 4 5 6 3 1 2 Sample Output 18 HINT

【醒目】【业界偷懒】【Public】BZOJ题目一句话题解整理

就当是复习一下自己做过的题,顺便提供一个简要题解给大家看. 做题时候实在想不出来看一下一句话题解,可以有一个提示的作用又不至于一下子知道了全部浪费了一道题吧.. 部分题目(如我A过得大部分奶牛题)是别人拿我的账号做的,不提供题解. 可能会漏掉很多做过的题..因为可能点页数不小心点错了什么的 UPD.本来想把那些没写过但是知道题解的也写了..但是写完这些已经累死了QAQ 已AC的题目(数学题均不提供分析过程,公式): 1000:A+B 1001:平面图最小割,转对偶图最短路 1002:矩阵树定理,

BZOJ 2653 middle 题解

题意:一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给一个序列,并进行一些询问.每次询问起点在[a,b],终点在[c,d]的序列的中位数. 题解:首先有一个思路:对于一个序列S,假设它的中位数是m,则S中>=m的元素个数一定>=n 那么对于一个序列S和一个数m,我们将>=m的元素设置为1,其余为-1,得到一个新数列S‘.则$\sum S'$ >=0 对于每个询问我们二分一下m即可.如果在区间[a,d]内有一段包含[b,c

BZOJ 4236~4247 题解

BZOJ 4236 JOIOJI f[i][0..2]表示前i个字符中′J′/′O′/′I′的个数 将二元组<f[i][0]?f[i][1],f[i][1]?f[i][2]>扔进map,记录一下最早出现的时间 对于每个位置去map里面查一下即可 时间复杂度O(nlogn) #include <map> #include <cstdio> #include <cstring> #include <iostream> #include <alg