• 7.19复习笔记


    突然忘了二维前缀和怎么写了

    dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+map[i][j];
    dp[x2][y2]+dp[x1-1][y1-1]-dp[x1-1][y2]-dp[x2][y1-1]
    

    一、高斯消元

    图上高斯消元,树上可以用树形dp替代

    void Gauss(int rowline,int colline,double a[][maxn]){
    	for (int i = 1;i <= rowline;i++){
    		int rowId = i;
    		for (int j = i+1;j <= rowline;j++){
    			if (fabs(a[j][i]) > fabs(a[rowId][i])) rowId = j;
    		}
    		if (rowId != i){
    			for (int j = i;j <= colline+1;j++) swap(a[i][j],a[rowId][j]);
    		}
    		if (a[i][i] == 0){
    			printf("No Solution
    ");return;
    		}
    		for (int j = i+1;j <= rowline;j++){
    			double tmp = a[j][i]/a[i][i];
    			for (int k = i;k <= colline+1;k++){
    				a[j][k] -= a[i][k]*tmp;
    			}
    		}
    	}
    	for (int i = rowline;i >= 1;i--){
    		for (int j = i+1;j <= colline;j++){
    			a[i][colline+1] -= a[i][j]*a[j][colline+1];
    		}
    		a[i][colline+1] /= a[i][i];
    	}
    	for (int i = 1;i <= rowline;i++) printf("%.2lf
    ",a[i][colline+1]);
    }
    int n;double A[maxn][maxn];
    int main(){
    	n = read();
    	for (int i = 1;i <= n;i++){
    		for (int j = 1;j <= n+1;j++) scanf ("%lf",&A[i][j]);
    	}
    	Gauss(n,n,A);
    	return 0;
    } 
    

    二、整体二分

    在信息学竞赛中,有一部分题可以使用二分的办法来解决。但是当这种题目有多次询问且每次询问我们对每个查询都直接二分,可能会收获一个 TLE。这时候我们就会用到整体二分。整体二分的主体思路就是把多个查询一起解决。(所以这是一个离线算法)

    可以使用整体二分解决的题目需要满足以下性质:

    1.询问的答案具有可二分性

    2.修改对判定答案的贡献互相独立,修改之间互不影响效果

    3.修改如果对判定答案有贡献,则贡献为一确定的与判定标准无关的值

    4.贡献满足交换律,结合律,具有可加性

    5.题目允许使用离线算法

    算法流程:

    记[l,r]为答案的值域,[L,R]为答案的定义域

    • 我们首先把所有操作按照时间的顺序存入数组中,进行分治

    • 在每一层分治中,统计当前查询的答案和mid之间的关系。

    • 根据查询出来的答案和mid间的关系(小于等于mid和大于mid)将当前处理的操作序列分为(q_1)(q_2)两份,并分别递归处理。

    • 当l == r时找到了答案

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #define B cout<<"Breakpoint"<<endl;
    #define O(x) cout<<#x<<" "<<x<<endl;
    #define o(x) cout<<#x<<" "<<x<<" ";
    using namespace std;
    int read(){
    	int x = 1,a = 0;char ch = getchar();
    	while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();}
    	while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();}
    	return x*a;
    }
    const int maxn = 505,maxq = 6e4+10,inf = 1e9+7;
    int n,Q;
    struct node{
    	int k,a1,b1,a2,b2,id,op;
    }q[maxq+maxn*maxn],q1[maxq+maxn*maxn],q2[maxq+maxn*maxn];
    int ans[maxq];
    int sum[maxn][maxn];
    void add(int x,int y,int k){
    	for (int i = x;i <= n;i += i&-i){
    		for (int j = y;j <= n;j += j&-j) sum[i][j] += k;
    	}
    }
    int query(int x,int y){
    	int res = 0;
    	for (int i = x;i;i -= i&-i){
    		for (int j = y;j;j -= j&-j) res += sum[i][j];
    	}
    	return res;
    }
    void solve(int l,int r,int nl,int nr){
    	if (l > r||nl > nr) return;
    	if (l == r){
    		for (int i = nl;i <= nr;i++) if (q[i].op == 2) ans[q[i].id] = l; 
    		return;
    	}
    	int cnt1 = 0,cnt2 = 0,mid = (l+r >> 1);
    	for (int i = nl;i <= nr;i++){
    		if (q[i].op == 1){
    			if (q[i].k <= mid) add(q[i].a1,q[i].b1,1),q1[++cnt1] = q[i];
    			else q2[++cnt2] = q[i];
    		}
    		else{
    			int res = query(q[i].a2,q[i].b2)-query(q[i].a1-1,q[i].b2)-query(q[i].a2,q[i].b1-1)+query(q[i].a1-1,q[i].b1-1);
    //			cout<<q[i].a1<<" "<<q[i].b1<<" "<<q[i].a2<<" "<<q[i].b2<<" "<<res<<endl; 
    			if (res >= q[i].k) q1[++cnt1] = q[i];
    			else q[i].k -= res,q2[++cnt2] = q[i];
    		}
    	}
    //	cout<<cnt1<<" "<<cnt2<<endl;
    	for (int i = 1;i <= cnt1;i++) if (q1[i].op == 1) add(q1[i].a1,q1[i].b1,-1);
    	for (int i = 1;i <= cnt1;i++) q[nl+i-1] = q1[i];
    	for (int i = 1;i <= cnt2;i++) q[nl+cnt1+i-1] = q2[i];
    	solve(l,mid,nl,nl+cnt1-1),solve(mid+1,r,nl+cnt1,nr); 
    }
    int cnt;
    int main(){
    	n = read(),Q = read();
    	for (int i = 1;i <= n;i++){
    		for (int j = 1;j <= n;j++){
    			int x = read();
    			q[++cnt] = (node){x,i,j,0,0,0,1};
    		}
    	}
    	for (int i = 1;i <= Q;i++){
    		int a1 = read(),b1 = read(),a2 = read(),b2 = read(),k = read();
    		q[++cnt] = (node){k,a1,b1,a2,b2,i,2};
    	}
    	solve(-inf,inf,1,cnt);
    	for (int i = 1;i <= Q;i++) printf("%d
    ",ans[i]);
    	return 0;
    }
    

    三、cdq分治

    这类问题一般是给你一个长度为 n 的序列,然后让你统计有一些特性的点对(i,j)有多少个,又或者说是找到一对点(i,j)使得一些函数的值最大之类的问题

    算法流程:

    1.找到当前序列中点mid

    2.将所有的点分为三类

    第一种是(1leq ileq mid 1leq jleq mid)

    第二种是(1leq mid+1 mid+1leq jleq n)

    第三种是(mid+1leq ileq n mid+1leq jleq n)

    3.将(1,n)序列分为两部分(1,mid)和(mid+1,n)

    会发现第一类点和第三类点分别被完全包含在两个序列

    这样我们只需要考虑如何求解第二类点

    void cdq(int l,int r){
    	if (l == r) return;
    	int mid = (l+r >> 1);
    	cdq(l,mid),cdq(mid+1,r);
    	sort(a+l,a+mid+1,cmpy),sort(a+mid+1,a+r+1,cmpy);
    	int j = l;
    	for (int i = mid+1;i <= r;i++){
    		while (a[j].y <= a[i].y&&j <= mid) add(a[j].z,a[j].w),j++;
    		a[i].ans += query(a[i].z;)
    	}
    	for (int i = l;i < j;i++) add(a[i].z,-a[i].w);
    }
    

    四、虚树

    如果整颗树的节点个数很多,每次查询都遍历一遍复杂度会炸

    但是如果保证了每次询问的关键点的Σ在正确的复杂度内,我们可以对关键点建虚树优化

    一般我们还会把1作为树根加到虚树中

    void build(int x){
    	if (top == 0){st[top = 1] = x;return;}
    	int LCA = lca(x,st[top]);
    	while (top > 1&&dep[LCA] < dep[st[top-1]]) ed2.add(st[top-1],st[top]),top--;
    	if (dep[LCA] < dep[st[top]]) ed2.add(LCA,st[top--]);
    	if (top == 0||LCA != st[top]) st[++top] = LCA;
    	st[++top] = x;
    } 
    for (int i = 1;i <= q;i++) build(k[i]);
    if (top) while (--top) ed2.add(st[top],st[top+1]);
    
  • 相关阅读:
    MsSql数据库存储过程加密解密
    Delete Exists
    SQL Server 2008数据库日志收缩
    MSSQL PIVOT 实现行列转置
    Oracle中将查询出的多条记录的某个字段拼接成一个字符串的方法
    oracle的分析函数over 及开窗函数
    Asprise-OCR的使用
    【整理】动态加载Web Services
    【转载】Python正则表达式指南
    Mac中PyCharm设置GitHub的步骤
  • 原文地址:https://www.cnblogs.com/little-uu/p/15031783.html
Copyright © 2020-2023  润新知