IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 牛客 前缀和专题 简要题解 -> 正文阅读

[数据结构与算法]牛客 前缀和专题 简要题解

链接:

前缀和专题

A:

做前缀乘即可,每次计算即
s u m [ r ] ? 逆 元 sum[r]*逆元 sum[r]? s u m l ? 1 m o ? 2 sum_{l-1} ^ {mo-2} suml?1mo?2?

代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

const int mo = 1000000007;
int a[100005], n, m;
ll sum[100005];

ll mul(ll x,ll y) {
    return (x*y-(ll)((long double)x/mo*y)*mo+mo)%mo;     
}

ll power(ll x, ll y) {
   if (x == 1) return 1;
   ll rp = 1;
   for (; y; y >>= 1) {
   	    if (y & 1) rp = mul(rp, x);
   	    x = mul(x, x);
   }	
   return rp;
}

int main() {
	scanf("%d%d", &n, &m);
	sum[0] = 1;
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]), sum[i] = 1ll*sum[i-1]*a[i]%mo;
    int l, r; 
	for (int i = 1; i <= m; i++) {
    	scanf("%d%d", &l, &r);
    	ll ans = mul(sum[r], power(sum[l-1],mo-2));
    	printf("%lld\n", ans);
	}	
}

B:

考虑二进制下每一位的贡献,即计算二进制下某一位 1 1 1的个数,
对于第 i i i位而言,
考虑集合 S S S n n n个数 a 1 , . . . , a n a_1,...,a_n a1?,...,an?
二进制下有 1 1 1的为 a p 1 , a p 2 , . . . , a p x a_{p1},a_{p2},...,a_{px} ap1?,ap2?,...,apx?
剩下 n ? x n-x n?x该位置为 0 0 0
发现 S S S的一个子集 T T T i i i位的异或和
只与 a p 1 , . , a p x a_{p1},.,a_{px} ap1?,.,apx?选择放在 T T T中的个数有关,奇数为 1 1 1,偶数为 0 0 0
所以该集合的子集能在该位产生贡献,显然要在 x x x个中选奇数个
∑ C x i \sum{C_{x}^{i}} Cxi? ( i < = x , 且 i 为 奇 数 ) (i<=x,且i为奇数) (i<=xi)
根据二项式定理该式 = 2 x ? 1 =2^{x-1} =2x?1
其他 n ? x n-x n?x a ? a_{-} a??可任选
S S S能在第 i i i位产生的贡献可计算为
2 i ? 2 x ? 1 ? 2 n ? x 2^i*2^{x-1}*2^{n-x} 2i?2x?1?2n?x
同理可算完 S S S的所有子集贡献
对于 S S S的超集的贡献,
因为相当于 S S S必选,在除 S S S的总集合中再任选
我们把 S S S中所有数都选上,得到一个总异或结果,记为 y y y
然后将
该结果 y y y与不包含 S S S的总集合做上述计算,得到贡献 n u m 1 num_1 num1?
再将不包含 S S S的总集合做上述计算,得到贡献 n u m 2 num_2 num2?
n u m 1 ? n u m 2 num_1-num_2 num1??num2? S S S的超集的总贡献

代码:

#include<bits/stdc++.h>

#define N 25

using namespace std;

typedef long long ll;

int num[N], a[N], b[N], c[N], n, m, tot;
bool orz[21];
ll mi[21];

int main() {
	mi[0] = 1; for (int i = 1; i <= 63; i++) mi[i] = mi[i-1]*2ll;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	int x, cnt;
	ll ans1, ans2;
	while (m--) {
		scanf("%d", &cnt);
		memset(orz, 0, sizeof(orz));
		for (int i = 1; i <= cnt; i++) scanf("%d", &x), b[i] = a[x], orz[x] = 1;
		//
		ans1 = 0;
		for (int i = 0; i < 20; i++) {
			x = 0;
			for (int j = 1; j <= cnt; j++) x += ((b[j] >> i) & 1);
		    if (x) ans1 += mi[i+(x-1)+(cnt-x)];
		    num[i] = x%2;
		}
		//
		ans2 = 0;
		tot = 0; for (int i = 1; i <= n; i++) if (!orz[i]) c[++tot] = a[i];
		for (int i = 0; i < 20; i++) {
			x = num[i];
			for (int j = 1; j <= tot; j++) x += ((c[j] >> i) & 1);
			if (x) ans2 += mi[i+(x-1)+((tot+1)-x)]; 
		}
		for (int i = 0; i < 20; i++) {
			x = 0;
			for (int j = 1; j <= tot; j++) x += ((c[j] >> i) & 1);
			if (x) ans2 -= mi[i+(x-1)+(tot-x)];
		}
		//
		printf("%lld %lld\n", ans1, ans2);
		
	}		
}

C:

多项式求高维前缀和差分,好像是板子题,先埋坑

D:

每次将插入的多项式丢到线段树对应区间,
线段树一个节点表示一个区间,且对应一个多项式,若多个多项式则合并
合并时候暴力将幂次相同的合并即可,因为多项式间可能开始的 f ( ) f() f()不同,合并多项式时以某个 f ( ) f() f()为标准,用二项式拆解另一个即可
所有插入完了以后将整颗线段树跑一遍,求出新的前缀和,然后 O ( 1 ) O(1) O(1)回答询问即可

代码:

#include<bits/stdc++.h>

#define N 100005

using namespace std;

typedef long long ll;

const ll mo = 1000000007;
struct Node {
	ll d[6]; int frt;
}T[N*5];
ll c[N][6], facinv[6], fac[6], inv[6], sum[N], a[N], b[6];
int cnt[N], n, m, q;

void read(ll &x) {
	ll f = 1; x = 0; char s = getchar();
	while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
	while (s >= '0' && s <= '9') { x = (ll)x*10+(s-'0'); s = getchar(); } 
	x = x*f;
}

void read1(int &x) {
	int f = 1; x = 0; char s = getchar();
	while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
	while (s >= '0' && s <= '9') { x = x*10+(s-'0'); s = getchar(); }
	x = x*f;
}

void pre_work() {
	inv[1] = 1; 
	for (int i = 2; i <= 5; i++) inv[i] = 1ll*(mo-mo/i)*inv[mo%i]%mo; 
	fac[0] = 1;
	for (int i = 1; i <= 5; i++) fac[i] = 1ll*fac[i-1]*i%mo;
	facinv[0] = 1; facinv[1] = 1;
	for (int i = 2; i <= 5; i++) facinv[i] = facinv[i-1]*inv[i]%mo;
}

ll Cnum(int x, int y) {
	if (!x || !y) return 1;
	return fac[x]*facinv[y]%mo*facinv[x-y]%mo;
}

void merge(int x, int num1, int num2) {
	if (!T[x].frt) {
		T[x].frt = num2; 
		for (int i = 0; i <= 5; i++) T[x].d[i] = c[num1][i];
	    return;
	}  
	int l = num2-T[x].frt;
	for (int i = 0; i <= 5; i++) {
		//c[num1][i]*num2^i
		//c[num1][i]*(T[x].frt+l)^i
		ll now = 1;
		for (int j = 0; j <= i; j++) {
			(T[x].d[i-j] += c[num1][i]*Cnum(i, j)%mo*now%mo) %= mo;
		    now = 1ll*now*l%mo;
		}
	}
}

void putdown(int x, int L, int R) {
	if (!T[x].frt) return;
	for (int i = 0; i <= 5; i++) c[m+1][i] = T[x].d[i];
	merge(x*2, m+1, T[x].frt); 
	int mid = (L+R)>>1;
	merge(x*2+1, m+1, T[x].frt+(mid-L+1));
	T[x].frt = 0;
}


void Insert(int now, int L, int R, int liml, int limr, int num1, int num2) {
	if (L == liml && R == limr) {
       merge(now, num1, num2); return;
	}
	putdown(now, L, R);
	int mid = (L+R)>>1;
	if (liml > mid) Insert(now*2+1, mid+1, R, liml, limr, num1, num2);
	   else if (limr <= mid) Insert(now*2, L, mid, liml, limr, num1, num2);
	        else Insert(now*2, L, mid, liml, mid, num1, num2), 
			     Insert(now*2+1, mid+1, R, mid+1, limr, num1, num2+(mid-liml+1));
}

void wycnzds(int now, int L, int R) {
	if (L == R) {
		if (T[now].frt) {
			ll per = 1;
		    for (int i = 0; i <= 5; i++) 
		        (a[L] += T[now].d[i]*per%mo) %= mo, per = 1ll*per*T[now].frt%mo;
	        (a[L] += mo) %= mo; 
		}
		return;
	} 
	putdown(now, L, R);
	int mid = (L+R)>>1;
	wycnzds(now*2, L, mid); wycnzds(now*2+1, mid+1, R);
}

void write(ll x) {
	if (x < 10) { putchar(x%10+'0'); return; }
	write(x/10); putchar(x%10+'0');
}
int main() {
	pre_work();
	read1(n); read1(m); read1(q);
	for (int i = 1; i <= n; i++) read(a[i]);
	int l, r;
	for (int i = 1; i <= m; i++) {
		read1(l); read1(r); read1(cnt[i]); 
		for (int j = 0; j <= cnt[i]; j++) read(c[i][cnt[i]-j]); 
		Insert(1, 1, n, l, r, i, 1);
	}
	wycnzds(1, 1, n);
	for (int i = 1; i <= n; i++) sum[i] = ((sum[i-1]+a[i])%mo+mo)%mo;
	ll ans;
	// 592 409 135 154 486
	for (int i = 1; i <= q; i++) {
		read1(l); read1(r);
		ans = (sum[r]-sum[l-1])%mo;
		(ans += mo) %= mo;
		write(ans); printf("\n");
	}
	return 0;
}

E:

f i , 0 , f i , 0 f_{i,0},f_{i,0} fi,0?,fi,0?表示到第 i i i层左,右的方案数
对于 f i , 0 f f_{i,0}f fi,0?f i , 1 ? > f i + 1 , 0 , f i + 1 , 1 _{i,1}->f_{i+1,0},f_{i+1,1} i,1??>fi+1,0?,fi+1,1?
发现无非就是2种转移矩阵,
1 1 1 0 0 0
1 1 1 1 1 1
或者
1 1 1 1 1 1
0 0 0 1 1 1

直接根据楼梯处理出每个点对应的矩阵
对于一个询问 ( h s , p s ) ? > ( h t , p t ) (hs,ps)->(ht,pt) (hs,ps)?>(ht,pt)
用线段树求出区间 [ h s , h t ] [hs,ht] [hs,ht]的矩阵乘积即可
因为线段树先序遍历的原因,不会对矩阵用到交换律,只会用到结合律,所以结果是正确的
求出矩阵区间乘积 y = y= y=
a a a b b b
c c c d d d
以后,考虑初态
根 据 p s 根据ps ps,选择矩阵 0 , 1 0,1 0,1或者 1 , 0 1,0 1,0
作为 f h s , 0 , f h s , 1 f_{hs,0},f_{hs,1} fhs,0?,fhs,1?初态
乘上矩阵 y y y即可得到 f h t , 0 , f h t , 1 f_{ht,0},f_{ht,1} fht,0?,fht,1?

代码:

#include<bits/stdc++.h>

#define N 100005

using namespace std;

typedef long long ll;

const int mo = 1000000007;

struct Matrix{
	ll a[3][3];
};
int n, m, hs, ht, ps, pt;
char s[N];
Matrix T[N*5], c[2], num;

void Pre_Work() {
	c[0].a[1][1] = 1; c[0].a[2][1] = 1; c[0].a[1][2] = 0; c[0].a[2][2] = 1;
	c[1].a[1][1] = 1; c[1].a[2][1] = 0; c[1].a[1][2] = 1; c[1].a[2][2] = 1;  
}

Matrix mul(Matrix aa, Matrix bb) {
	Matrix cc; memset(cc.a, 0, sizeof(cc.a)); 
	for (int i = 1; i <= 2; i++)
		for (int j = 1; j <= 2; j++)
		    for (int k = 1; k <= 2; k++) 
		        (cc.a[i][j] += aa.a[i][k]*bb.a[k][j]%mo) %= mo;
	return cc;
}

void Build(int now, int L, int R) {
    if (L == R) {
    	int opt = (s[L] == '/');
    	memcpy(T[now].a, c[opt].a, sizeof(c[opt].a));
		return;
	}	
	int mid = (L+R)>>1;
	Build(now*2, L, mid); 
	Build(now*2+1, mid+1, R);
	T[now] = mul(T[now*2], T[now*2+1]);
}

void Getmulsum(int now, int L, int R, int liml, int limr) {
	if (L == liml && R == limr) {
		if (num.a[1][1] == -1) memcpy(num.a, T[now].a, sizeof(T[now].a)); 
	       else num = mul(num, T[now]);
	    return;
	}
	int mid = (L+R)>>1;
	if (liml > mid) Getmulsum(now*2+1, mid+1, R, liml, limr);
	   else if (limr <= mid) Getmulsum(now*2, L, mid, liml, limr);
	        else Getmulsum(now*2, L, mid, liml, mid), Getmulsum(now*2+1, mid+1, R, mid+1, limr);
}

void Calc() {
	ll frt[3], ans[3];
	memset(num.a, 255, sizeof(num.a));
	Getmulsum(1, 1, n-1, hs, ht-1);
    if (!ps) frt[1] = 1, frt[2] = 0; else frt[1] = 0, frt[2] = 1;
    memset(ans, 0, sizeof(ans));
	for (int i = 1; i <= 2; i++) 
        for (int j = 1; j <= 2; j++)
		    (ans[i] += frt[j]*num.a[j][i]%mo) %= mo;
	for (int i = 1; i <= 2; i++) (ans[i] += mo) %= mo;
	printf("%lld\n", ans[pt+1]);
	
}

int main() {
	Pre_Work();
	scanf("%d%d", &n, &m);
	scanf("%s", s+1);
	Build(1, 1, n-1);
	for (int i = 1; i <= m; i++) 
		scanf("%d%d%d%d", &hs, &ht, &ps, &pt), Calc();
	return 0;
} 

F:

考虑经过前 a 1 a_1 a1?次操作, b 1 b_1 b1?位置是小球 k k k
经过前 a 2 a_2 a2?次操作,小球 k k k的位置是 b 2 b_2 b2?
那么我如果从初始状态,只经过操作 ( a 1 + 1 ) (a_1+1) (a1?+1)到操作 a 2 a_2 a2?
就相当于 b 1 b_1 b1?位置的 k k k变成了 b 1 b_1 b1?(初始状态位置i对应小球i),最后 b 1 b_1 b1? a 2 a_2 a2?对应的位置肯定就是原先 k k k对应的位置 b 2 b_2 b2?
那么一开始先预处理做一遍,
记录每次操作过后,位置 i i i是什么小球,小球 i i i在什么位置
每次询问直接回答即可

代码:

#include<bits/stdc++.h>

#define N 500005

using namespace std;

int a[N][10], b[N][10], n, m;
int ans[10];

int main() {
    scanf("%d%d", &n, &m);
	for (int i = 0; i < 10; i++) a[0][i] = i, b[0][i] = i;
	int x, y;
	for (int i = 1; i <= n; i++) {
		scanf("%d%d", &x, &y);
		for (int j = 0; j < 10; j++) b[i][j] = b[i-1][j];
		swap(b[i][x], b[i][y]);
		for (int j = 0; j < 10; j++) a[i][b[i][j]] = j; 
	}
	for (int i = 1; i <= m; i++) {
		scanf("%d%d", &x, &y);
		for (int j = 0; j < 10; j++) ans[a[y][b[x-1][j]]] = j;
		for (int j = 0; j < 9; j++) printf("%d ", ans[j]); printf("%d\n", ans[9]);
	}
//0 7 6 3 4 5 2 1 8 9

} 

G:

考虑从左向右扫遍,每个右移会使左边的所有 l i n k link link点对接下来的 l i n k link link点的相对位置+1,
记录 l i n k link link点数目,以及相对距离和
每次到 l i n k link link点直接统计即可

代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int mo = 1000000007;

ll dis, ans;
int siz, n;
char s[100005];

int main() {
//	freopen("data.in", "r", stdin);
	scanf("%d", &n);
	scanf("%s", s+1);
	for (int i = 1; i <= n; i++) {
		if (s[i] == '1') (ans += dis) %= mo, ++siz;
		(dis += 1ll*siz)  %= mo;
	}
	printf("%lld\n", ans);
	return 0;
}

H:

在这里插入图片描述

代码:

#include<bits/stdc++.h>

#define N 100005

using namespace std;

typedef long long ll;

const int mo = 1000000007;

int a[4][N], sum[N], n, m, T;
ll now1;
ll now2, siz2;
ll now3, siz3, now33;
ll ans;

void pre_work() {
	now1 = 0; 
	now2 = 0; siz2 = 0;
	now3 = 0; siz3 = 0; now33 = 0;
    for (int i = 1; i <= 3; i++) 
        for (int j = 1; j <= n; j++) a[i][j] = 0;
}

int main() {
//	freopen("data.in", "r", stdin);
	scanf("%d", &T);
	int type, pos;
	while (T--) {
        scanf("%d%d", &n, &m);
    	pre_work();	
		for (int i = 1; i <= m; i++) scanf("%d%d", &type, &pos), ++a[type][pos];
		for (int i = 1; i <= n; i++) {
			if (a[1][i]) (now1 += a[1][i]) %= mo;
			//
			if (a[2][i]) (siz2 += a[2][i]) %= mo; 
			(now2 += siz2) %= mo;
			// 
			(now33 += 2ll*now3%mo+siz3%mo) %= mo;
			(now3 += siz3) %= mo;
			if (a[3][i]) 
			   (siz3 += a[3][i]) %= mo, 
			   (now3 += a[3][i]) %= mo,
			   (now33 += a[3][i]) %= mo;  
			//
			ans = ((now1+now2)%mo+now33)%mo;
			(ans += mo) %= mo;
			if (i < n) printf("%lld ", ans); 
		}
		printf("%lld\n", ans);
    }
	return 0;
}

I:

显然做差,大于 0 0 0的差值的计入答案即可

代码:

#include<bits/stdc++.h>

#define N 100005

using namespace std;

int h[N], c[N], n, ans;

int main() {
	scanf("%d",&n);
	for (int i = 1; i <= n; i++) scanf("%d", &h[i]);
	for (int i = 1; i <= n; i++) c[i] = h[i]-h[i-1];
	for (int i = 1; i <= n; i++) 
	    if (c[i] > 0) ans += c[i];
	printf("%d\n", ans);
	return 0;
}

J:

也是做差,然后直接计算正的差值

代码:

在这里插入代码片#pragma GCC optimize(3)
#include <iostream>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)
#define mt(x) memset(x, 0, sizeof(x))
#define mp(x, y) memcpy(x, y, sizeof(y))
#define lson(x) x * 2 
#define rson(x) x * 2 + 1

#define N 100005
 
using namespace std;

typedef long long ll;

int a[N], n;
ll ans;

int read(int &x) {
	int f = 1; x = 0; char s = getchar();
	while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
	while (s >= '0' && s <= '9') { x = x * 10 + (s - '0'); s = getchar(); }
	return x * f;
}

int main() {
//	frepen("data.in", "r", stdin);
	read(n);
	rep(i, 1, n) read(a[i]);
	rep(i, 1, n) if (a[i] > a[i - 1]) ans = ans + (ll)(a[i] - a[i - 1]);
	printf("%lld\n", ans); 
	return 0;
} 
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-18 12:56:50  更:2021-08-18 12:59:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年4日历 -2025/4/4 8:25:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码