# 8.19考试总结
8.19考试总结
预计得分:230 实际得分:180 丢分:50
真的是哪题不拍挂哪题
T1
方差的式子是
\[\frac{\sum a_i^2}{n} - \frac{(\sum a_i)^2}{n^2}
\]
题目中式子其实要求的是
\[n\sum a_i^2-(\sum a_i)^2
\]
想DP发现这两个东西不好同时搞
我们就DP一维记录一维
记录肯定考虑记录值域最小的
我们就设\(f_{i,j,k}\)他去表示
到了\((i,j)\)这个点
\(\sum a_i\)的值为\(k\)的最大的\(\sum a_i^2\)
转移显然
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 35;
const int M = 1835;
int f[N][N][M];
int a[N][N];
int n,m;int num = 0;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int main(){
// freopen("path.in","r",stdin);
int T = read();
while(T--){
memset(f,0x3f,sizeof(f));
n = read(),m = read();
for(int i = 1;i <= n;++i)
for(int j = 1;j <= m;++j) a[i][j] = read();//cout << "GG" << endl;
// memset(f,0x3f,sizeof(f));
f[1][1][a[1][1]] = a[1][1] * a[1][1];
for(int i = 1;i <= n;++i){
for(int j = 1;j <= m;++j){
for(int k = 0;k <= (i + j - 1) * 30;++k){
if(k + a[i + 1][j] <= (i + j) * 30) f[i + 1][j][k + a[i + 1][j]] = min(f[i + 1][j][k + a[i + 1][j]],
f[i][j][k] + a[i + 1][j] * a[i + 1][j]);
if(k + a[i][j + 1] <= (i + j) * 30) f[i][j + 1][k + a[i][j + 1]] = min(f[i][j + 1][k + a[i][j + 1]],
f[i][j][k] + a[i][j + 1] * a[i][j + 1]);
// if(k + a[i + 1][j] > (i + j) * 30)
}
}
}
LL ans = 0x3f3f3f3f;
for(int i = 0;i <= 1800;++i) ans = min(ans,1ll * (n + m - 1) * f[n][m][i] - i * i);
printf("Case #%d: %lld\n",++num,ans);
}
return 0;
}
T2
挂烂了QAQ
考虑优雅的暴力建边
这是暴力建边方式时间复杂度\(O(nm)\)
正确性显然
发现每次都是一个点向一个区间连边,直接线段树优化这个过程
而由于边权只有\(1/0\)
最短路径可以\(01\)bfs
关于线段树优化建图的本质,这里就简单的说一下
本质是维护了两颗线段树,一颗表示入边另外一颗表示出边
区间操作就可以通过虚点来进行连接
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#include<deque>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 1e6 + 3;
int pos[N];
int n,m,s;
int whe;
struct tree{
int head[N << 2];
int dis[N << 2];
int rt1,rt2,tot,t;
struct node{
int lc;
int rc;
}a[N << 2];
struct edge{
int to;
int nxt;
int data;
}e[N * 35];
inline void add(int x,int y,int z){
e[++tot].to = y;
e[tot].data = z;
e[tot].nxt = head[x];
head[x] = tot;
}
inline void build(int &u,int l,int r,bool flag){
if(!u) u = ++t;
if(l == r) {if(!flag) pos[l] = u;return;}
int mid = (l + r) >> 1;
build(a[u].lc,l,mid,flag);build(a[u].rc,mid + 1,r,flag);
if(flag){
add(a[u].lc,u,0);
add(a[u].rc,u,0);
}
else{
add(u,a[u].lc,0);
add(u,a[u].rc,0);
}
}
inline void updata(int u,int l,int r,int ll,int rr,int p,bool flag){
if(l == ll && r == rr){
if(flag) add(u,p,0);
else add(p,u,0);
return ;
}
int mid = (l + r) >> 1;
if(rr <= mid) updata(a[u].lc,l,mid,ll,rr,p,flag);
else if(ll > mid) updata(a[u].rc,mid + 1,r,ll,rr,p,flag);
else{
updata(a[u].lc,l,mid,ll,mid,p,flag);
updata(a[u].rc,mid + 1,r,mid + 1,rr,p,flag);
}
}
inline void ADD(int r1,int r2,int l,int r){
if(l == r){
add(r2,r1,0);
return ;
}
int mid = (l + r) >> 1;
ADD(a[r1].lc,a[r2].lc,l,mid);ADD(a[r1].rc,a[r2].rc,mid + 1,r);
}
inline void link(int l,int r,int ll,int rr){
updata(rt1,1,n,l,r,++t,1);
updata(rt2,1,n,ll,rr,++t,0);
add(t - 1,t,1);
}
inline void bfs(int x){
memset(dis,0x3f,sizeof(dis));
dis[x] = 0;
deque <int> q;
q.push_back(x);
while(!q.empty()){
int k = q.front();
q.pop_front();
for(int i = head[k];i;i = e[i].nxt){
int y = e[i].to;
if(dis[y] > dis[k] + e[i].data){
dis[y] = dis[k] + e[i].data;
if(e[i].data) q.push_back(y);
else q.push_front(y);
}
}
}
for(int i = 1;i <= n;++i) printf("%d\n",dis[pos[i]]);
}
}T;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int main(){
n = read(),m = read(),s = read();
T.build(T.rt1,1,n,1);
T.build(T.rt2,1,n,0);
T.ADD(T.rt1,T.rt2,1,n);
for(int i = 1;i <= m;++i){
int l = read(),r = read(),ll = read(),rr = read();
T.link(l,r,ll,rr);
T.link(ll,rr,l,r);
}
// printf("%d\n",pos[s]);
T.bfs(pos[s]);
return 0;
}
T3
\(n = 1000\)被我\(n^3\)卡过去了可还行
我到现在还是怀疑题解的思路是错的,
说一下另外一个\(n^2\)做法
把矩阵查分两次之后
就变成了求最大的全\(0\)子矩阵(可能细节和边界要特殊处理)
这个直接悬线法求就好了