【分块】CODEFORCES 384C Subset Sums

通道

题意:给出n个数,m组序列,然后每次可以选择一个序列给对应的每个数加定值,及询问该组对应数之和

思路:可以知道修改某一组后,肯定对应和其他组有相交部分也要对应修改,每次去修改肯定不现实,然后对于sqrt(n)以内的数可以O(n)修改,其他的只要计算对应的增量即可,然后维护对于大于sqrt(n)的序列会影响到哪些小于sqrt(n)的序列即可。

代码:

#include <cstdio>
#include  <cmath>
#include <vector>
using namespace std;

typedef long long ll;
const int N = 100005;
const int M = 333;

int n , m , q;
int size[N], id[N];
int bigcnt = 0, vis[N];
int inter[N][M];
ll a[N];
ll ans[N] , update[N];
vector<int> num[N];

int main() {
    scanf("%d%d%d" , &n , &m , &q);
    for (int i = 1 ; i <= n ; i ++) {
        scanf ("%I64d" , &a[i]);
    }
    int limit = (int)sqrt (n) + 1;
    for (int i = 1 ; i <= m ; i ++) {
        scanf ("%d" , &size[i]);
        num[i].resize(size[i]);
        for (int j = 0 ; j < size[i] ; j ++) {
            scanf ("%d" , &num[i][j]);
        }
        if (size[i] >= limit) {
            id[i] = bigcnt++;
        } else id[i] = -1;
    }
    for (int i = 1 ; i <= m ; i ++)
        if (id[i] != -1) {
            for (int j = 0 ; j < size[i] ; j ++) {
                vis[num[i][j]] = i;
                ans[id[i]] += a[num[i][j]];
            }
            for (int j = 1 ; j <= m ; j ++) {
                for (int k = 0 ; k < size[j] ; k ++)
                    if (vis[num[j][k]] == i)
                        inter[j][id[i]]++;
            }
        }
    while (q --) {
        char str[5];int idx;
        scanf ("%s%d" , str , &idx);
        if (str[0] == ‘?‘) {
            if (id[idx] == -1) {
                ll ret = 0;
                for (int i = 0 ; i < size[idx] ; i ++)
                    ret += a[num[idx][i]];
                for (int i = 0 ; i < bigcnt ; i ++)
                    ret += 1LL * update[i] * inter[idx][i];
                printf ("%I64d\n" , ret);
            } else printf ("%I64d\n" , ans[id[idx]]);
        } else {
            int x; scanf ("%d" , &x);
            for (int i = 0 ; i < bigcnt ; i ++)
                ans[i] += 1LL * inter[idx][i] * x;
            if (id[idx] == -1) {
                for (int i = 0 ; i < size[idx] ; i ++)
                    a[num[idx][i]] += x;
            } else update[id[idx]] += x;
        }
    }
    return 0;
}

时间: 2025-01-12 11:45:53

【分块】CODEFORCES 384C Subset Sums的相关文章

洛谷P1466 集合 Subset Sums

洛谷P1466 集合 Subset Sums这题可以看成是背包问题 用空间为 1--n 的物品恰好填充总空间一半的空间 有几种方案 01 背包问题 1.注意因为两个交换一下算同一种方案,所以最终 要 f [ v ] / 2 2.要开 long long 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string&g

CodeForces 837F - Prefix Sums | Educational Codeforces Round 26

按tutorial打的我血崩,死活挂第四组- - 思路来自FXXL /* CodeForces 837F - Prefix Sums [ 二分,组合数 ] | Educational Codeforces Round 26 题意: 设定数组 y = f(x) 使得 y[i] = sum(x[j]) (0 <= j < i) 求初始数组 A0 经过多少次 f(x) 后 会有一个元素 大于 k 分析: 考虑 A0 = {1, 0, 0, 0} A1 = {1, 1, 1, 1} -> {C(

Project Euler 106:Special subset sums: meta-testing 特殊的子集和:元检验

Special subset sums: meta-testing Let S(A) represent the sum of elements in set A of size n. We shall call it a special sum set if for any two non-empty disjoint subsets, B and C, the following properties are true: S(B) ≠ S(C); that is, sums of subse

Codeforces 126D Fibonacci Sums 求n由任意的Sum(fib)的方法数 dp

题目链接:点击打开链接 题意: 给定一个数n 问把这个数拆成多个不相同的fibonacci数 有多少种拆法 #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<math.h> #include<set> #include<queue> #include<vector> #include<m

Subset Sums

链接 分析:dp[i][j]表示前i个数能够组成j的对数,可得dp[i][j]=dp[i-1][j]+dp[i-1][j-i],所以最后dp[n][sum/2]既是所求 1 /* 2 PROB:subset 3 ID:wanghan 4 LANG:C++ 5 */ 6 #include "iostream" 7 #include "cstdio" 8 #include "cstring" 9 #include "string"

【USACO 2.2】Subset Sums (DP)

N (1 <= N <= 39),问有多少种把1到N划分为两个集合的方法使得两个集合的和相等. 如果总和为奇数,那么就是0种划分方案.否则用dp做. dp[i][j]表示前 i 个数划分到一个集合里,和为j的方法数. dp[i][j]=dp[i-1][j]+dp[i][j-i] n 为 39 时,1 到 39 的和为 780,枚举 j 的时候枚举到 s/2,最后输出dp[n][s/2]/2. http://train.usaco.org/usacoprob2?a=z5hb7MFUmsX&

usaco Subset Sums

题意是将1到N的N个数分为两组,要求这两组数字和相等,问有多少种分法 第一遍暴力超时,后来在网上找了才知道是dp,然后这道题的dp方程和01背包有点像,dp[i][j]=dp[i-1][j]+dp[i-1][j-N]; 方程的意思是在i个数字里选出总和为j的方案数,等于在i-1个数里,选出总和为j的方案数(没有i),加上在i-1个数里选出总和j-i的方案数(再加上后来的i,就等于j). 因为返程和01背包很像,所以也能使用和01背包一样的方法优化空间 /* ID: modengd1 PROG:

USACO Section 2.2 Subset Sums

/* ID: lucien23 PROG: subset LANG: C++ */ #include <iostream> #include <fstream> using namespace std; int main() { ifstream infile("subset.in"); ofstream outfile("subset.out"); if(!infile || !outfile) { cout << "

【USACO】Subset Sums(双向搜索 dfs)

给你一组数 1 ~ N,问你能有几种分法,把他们分成2组,2组的和相等. 如果 sum(1 ~ n) 为奇数,直接输出0,负责的话 主要找到 和为 sum / 2的组数 再除以2就是结果 因为N 最大为39 如果单向搜索肯定超时,改成双向的就行了 /* ID: 18906421 LANG: C++ PROG: subset */ #include<cstdio> #include<cstring> #include<iostream> #include<vecto