(分块暴力)Time to Raid Cowavans CodeForces - 103D

题意

给你一段长度为n(1 ≤ n ≤ 3·1e5)的序列,m (1 ≤ p ≤ 3·1e5)个询问,每次询问a,a+b,a+2b+...<=n的和

思路

一开始一直想也想不到怎么分,去维护哪些信息,看了题解才知道 其实分块不仅仅可以将一列序列分块,还可以将数据进行分块,下面讨论具体做法

首先这道题不是在线询问,可以离线做,先读入所有的询问,将询问从小到大排序
①当b<√n时,对于每一个b我们可以预处理出这样的一个数组sum[i],就是以i为起点间隔为b的序列和(可以用一个简单的dp求出来),然后O(1)查询,这么做的好处就是如果不同的询问a不同,b相同,经过排序我们就可以直接使用这个sum数组,时间复杂度为O(n√n)。
②当b≥√n时,直接暴力求和,时间复杂度为O(m√n)
所以总时间复杂度为O((m+n)√n)

#include<iostream>
#include<algorithm>
#include<cmath>
 using namespace std;
 const int maxn=3e5+10;
 typedef long long ll;
 ll a[maxn];
 struct node{
     int a,b,id;
     bool operator<(const node &s) const
     {
         return b<s.b;
     }
 }b[maxn];
 ll ans[maxn];
 ll sum_b[maxn];
 int main()
 {
     int n,m;
     scanf("%d",&n);
     int bl=sqrt(n);
     for(int i=1;i<=n;i++)
         scanf("%I64d",&a[i]);
     scanf("%d",&m);
     for(int i=1;i<=m;i++){
         b[i].id=i;
         scanf("%d%d",&b[i].a,&b[i].b);
     }
     sort(b+1,b+1+m);
     b[0].b=0;
    for(int i=1;i<=m;i++){
        if(b[i].b>=bl){
            ans[b[i].id]=0;
            for(int k=b[i].a;k<=n;k+=b[i].b)
                ans[b[i].id]+=a[k];
        }
        else{
            if(b[i].b==b[i-1].b){
                ans[b[i].id]=sum_b[b[i].a];
            }
            else{
                for(int j=n;j>=1;j--)
                    if(j+b[i].b>n)
                        sum_b[j]=a[j];
                    else
                        sum_b[j]=sum_b[j+b[i].b]+a[j];
                ans[b[i].id]=sum_b[b[i].a];
            }
        }
    }
    for(int i=1;i<=m;i++)
        printf("%I64d\n",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/overrate-wsj/p/12168925.html

时间: 2024-11-09 10:50:24

(分块暴力)Time to Raid Cowavans CodeForces - 103D的相关文章

Codeforces#86D Powerful array(分块暴力)

Description An array of positive integers a1,?a2,?...,?an is given. Let us consider its arbitrary subarray al,?al?+?1...,?ar, where 1?≤?l?≤?r?≤?n. For every positive integer s denote by Ks the number of occurrences of s into the subarray. We call the

CodeForces 103 D Time to Raid Cowavans

Time to Raid Cowavans 题意:一共有n头牛, 每头牛有一个重量,m次询问, 每次询问有a,b 求出 a,a+b,a+2b的牛的重量和. 题解:对于m次询问,b>sqrt(n)的时候我们直接把结果跑出来,当b<sqrt(n)的时候我们离线询问,算出所有一个b的任意一起点的值. 复杂度为 q*sqrt(n); 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen(&q

【CF103D】Time to Raid Cowavans [根号算法]

CF103D Time to Raid Cowavans 一个序列\(a\),\(m\)次询问,每次询问给出\(t,k\),求\(a_t+a_{t+k}+a_{t+2k}+...+a_{t+pk},t+(p+1)k>n\) 步长\(k\ge\sqrt n\)时暴力枚举 \(k<\sqrt n\)时预处理出来部分和\(O(n\sqrt n)\) 但是这样会MLE 所以用一个\(sum\)数组 将询问离线询问 \(<\sqrt n\)的\(k\)不会超过\(\sqrt n\)个 所以复杂度不

Light OJ 1339 Strongest Community(分块暴力)

In a strange city, houses are built in a straight line one after another. There are several communities in the city. Each community consists of some consecutivehouses such that every house belongs to exactly one community. The houses are numbered fro

D. Time to Raid Cowavans 分块暴力,感觉关键在dp

对于b大于 sqrt(n)的,暴力处理的话,那么算出每个的复杂度是sqrt(n),就是把n分成了sqrt(n)段, 其他的,b小于sqrt(n)的,那么就最多只有sqrt(n)个,考虑到,如果b相同的话,放在一起,能不能记录一个结果呢? 用dp[pos]表示从pos这个位置开始,间隔为b的答案值. 那么需要从后面往前dp,每次转移dp[i] = dp[i + b] + a[i]即可 #include <cstdio> #include <cstdlib> #include <

CodeForces 103D 分块处理

题目链接:http://codeforces.com/problemset/problem/103/D 题意:给定一个长度为n的序列.然后q个询问.每个询问为(a,b),表示从序列第a项开始每b项的加和. 思路:2014集训队论文中的<<根号算法——不只是分块>>中提到这题. 传统的数据结构比较擅长处理连续区间的询问.但是不擅长处理间隔位置的询问.考虑到分块. 对于b>sqrt(n)的询问.我们暴力计算.可以发现b越大我们扫描的位置就会越小.最大扫描次数为O(n/sqrt(n

D. Alyona and a tree 公式转换 + 分块暴力

http://codeforces.com/problemset/problem/740/D 对于每一对<u, v>.设dis[u]表示root到点u的距离,那么dis<u去v>就是dis[v] - dis[u], 就是在它的儿子中找出有多少个v使得dis[v] - dis[u] <= a[v].然后,因为如果v确定了,那么dis[v]和a[v]就确定了. 所以把公式转换为dis[v] - a[v] <= dis[u]. 那么可以暴力枚举每一个u,然后在其儿子中找有多少

BZOJ 2002 Bounce 弹飞绵羊(分块|暴力|)(困难)

Bounce 弹飞绵羊 Time Limit:10000MS     Memory Limit:265216KB     64bit IO Format:%lld & %llu Submit Status Practice HYSBZ 2002 Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后

HDU - 4366 Successor DFS序 + 分块暴力 or 线段树维护

给定一颗树,每个节点都有忠诚和能力两个参数,随意指定一个节点,要求在它的子树中找一个节点代替它,这个节点要满足能力值大于它,而且是忠诚度最高的那个. 首先,dfs一下,处理出L[i], R[i]表示dfs序,则R[i] - L[i] + 1 就是当前i这个节点拥有的子孙个数. 对于一颗树,dfs的时候,访问节点有先后顺序,那么可以用一个struct node List[maxn];表示这课树中访问的先后顺序. 例如这颗树,我假设是先访问0 --> 3 --> 2 ---> 4 ---&g