NOI前集训日志
持续更新。。
[Day1 2016-7-1]
水题赛被虐记
T1 cycle 求一个图中的负环,使它的点数最小 n <= 300
因为是求环,想一下O(n^3),floyd可以求最小环,可以倍增这个东西,先搞出来矩阵的2^n,再从大到小确定,如果这一位不乘便没有负环的话就必须要这一位
#define MAXN 310
#include <algorithm>
#include <cstdio>
using namespace std;
const int inf = 1e9;
int n, m;
struct Node {
int a[MAXN][MAXN];
void init() {
for(int i = 1 ; i <= n ; ++ i) {
for(int j = 1 ; j <= n ; ++ j) {
a[i][j] = inf;
}
}
}
void print() {
for(int i = 1 ; i <= n ; ++ i) {
for(int j = 1 ; j <= n ; ++ j) {
printf("%d ", a[i][j]);
}puts("");
}
}
}mat[10], nw, tp;
Node operator * (const Node& a, const Node& b) {
Node ret; ret.init();
for(int i = 1 ; i <= n ; ++ i)
for(int j = 1 ; j <= n ; ++ j)
ret.a[i][j] = min(a.a[i][j], b.a[i][j]);
for(int k = 1 ; k <= n ; ++ k)
for(int i = 1 ; i <= n ; ++ i)
for(int j = 1 ; j <= n ; ++ j)
ret.a[i][j] = min(ret.a[i][j], a.a[i][k] + b.a[k][j]);
return ret;
}
void cmin(int& a, int b) {
if(a > b) a = b;
}
int main() {
freopen("cycle.in", "r", stdin);
freopen("cycle.out", "w", stdout);
scanf("%d%d", &n, &m);
int u, v, w, Mx = 1, lg = 0;
mat[0].init();
for(; Mx<<1 <= n ; Mx<<=1, lg ++);
for(int i = 1 ; i <= m ; ++ i) {
scanf("%d%d%d", &u, &v, &w);
cmin(mat[0].a[u][v], w);
}
for(int i = 1 ; i <= lg ; ++ i)
mat[i] = mat[i-1] * mat[i-1];
//mat[lg].print();
int ans = 0;
for(; Mx; Mx >>= 1, lg --) {
tp = ans ? nw * mat[lg] : mat[lg];
bool fg = false;
for(int i = 1 ; i <= n ; ++ i)
if(tp.a[i][i] < 0){
fg = true;
break;
}
if(fg) continue;
nw = tp;
ans ^= Mx;
}
if(ans < n)printf("%d\n", ans+1); else printf("0\n");
return 0;
}
T2 road 给一个图,使得i与n-i+1联通,其中i<=d, d <= 4, d <= n / 2
复习了一下斯坦纳树,两个方程,1.斯坦纳树的两个子树合并,如果小于inf就放进队列中;2.向外延伸(spfa)
#define MAXN 100010
#include <cstdio>
#include <queue>
using namespace std;
const int inf = 1e9;
int n, m, d, ans = inf;
int h[MAXN], cnt;
struct Edge{int to, nxt, dis;}edge[MAXN];
void addedge(int u, int v, int d) {
edge[++ cnt] = (Edge){v, h[u], d}; h[u] = cnt;
edge[++ cnt] = (Edge){u, h[v], d}; h[v] = cnt;
}
int f[10010][256], dp[256], vis[MAXN];
queue<int> q;
void spfa(int sta) {
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = h[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to;
if(f[v][sta] > f[u][sta] + edge[i].dis) {
f[v][sta] = f[u][sta] + edge[i].dis;
if(!vis[v])q.push(v), vis[v] = true;
}
}vis[u] = false;
}
}
int solve(int Max_s) {
for(int i = 1 ; i <= n ; ++ i)
for(int j = 0 ; j < Max_s ; ++ j)
f[i][j] = inf;
for(int i = 1 ; i <= d ; ++ i) {
f[i][1<<i-1] = 0;
f[n-i+1][1<<(i-1+d)] = 0;
//printf("%d %d\n", 1<<i-1, 1<<(i-1+d));
}
for(int sta = 0 ; sta < Max_s ; ++ sta) {
//int x = sta >> d, y = sta & ((1<<d)-1); if(x != y) continue;
for(int i = 1 ; i <= n ; ++ i) {
for(int j = h[i]; j; j = edge[j].nxt) {
int v = edge[j].to;
for(int s = sta&(sta-1) ; s ; s = (s-1)&sta)
f[i][sta] = min(f[i][sta], f[i][s] + f[v][sta^s] + edge[j].dis);
}
if(f[i][sta] != inf) q.push(i), vis[i] = 1;
}spfa(sta);
}
}
int main() {
freopen("road.in", "r", stdin);
freopen("road.out", "w", stdout);
scanf("%d%d%d", &n, &m, &d);
int u, v, w;
for(int i = 1 ; i <= m ; ++ i) {
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
}
int S = 1 << (2*d);
solve(S);
dp[0] = 0;
int T = 1 << d;
for(int i = 1 ; i < T ; ++ i) {
int to = i<<d|i, ret = inf;
for(int j = 1 ; j <= n ; ++ j)
ret = min(ret, f[j][to]);
dp[to] = ret;
}
for(int i = 0 ; i < T ; ++ i) {
int nw = i << d | i;
for(int j = 0 ; j <= i ; ++ j) {
if((i & j) != j) continue;
int to = j << d | j;
dp[nw] = min(dp[to] + dp[nw^to], dp[nw]);
//if(i == 15)printf("%d %d\n", nw^to, to);
}
}
//for(int i = 0 ; i < S ; ++ i)printf("dp[%d] = %d\n", i, dp[i]);puts("");
ans = dp[S-1];
if(ans != inf) printf("%d\n", ans); else puts("-1");
return 0;
}
T3 network
给定一棵边权均为1 的无根树,点可能是黑色或白色,支持两种操作。
• 1 xi pi 表示目前点xi 的颜色可能发生了翻转(白变黑,黑变白),发生概率为pi%。
• 2 si 表示求E(( Σ(x=black, dist(x, si)) ) ^ 2)
这个平方就是一堆和相乘,这样把和分配给两项,每两两组合的a*b的sigma
我要求的答案就是p[i] * p[j] * dist(i, s) * dist(j, s) (p[i]为i是黑点的概率)
注意当i = j的时候,贡献是p[i] * dist(i, s) ^ 2, 因为p[i]代表i是黑点
那么我们要求的答案Ans = (Σp[i]*dist(i,s)) ^ 2 - Σp[i]^2 * dist(i, s)^2 + Σp[i] * dist(i, s)^2
用动态树分治做就可以了
#define MAXN 200010
#include <algorithm>
#include <cstdio>
using namespace std;
const int inf = 1e9;
int n, m, h[MAXN], cnt;;
struct Edge { int to, nxt; }edge[MAXN<<1];
void addedge(int u, int v) {
edge[++ cnt] = (Edge){v, h[u]}; h[u] = cnt;
edge[++ cnt] = (Edge){u, h[v]}; h[v] = cnt;
}
//------------------------------------------------------------------------------------//
int c[MAXN], fa[MAXN], dep[MAXN], st[MAXN][20], pos[MAXN], lg[MAXN], amt;
inline int Min(int i, int j) {
return dep[i] < dep[j] ? i : j;
}
void dfs(int u) {
dep[u] = dep[fa[u]] + 1;
st[++ amt][0] = u;
pos[u] = amt;
for(int i = h[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to;
if(v == fa[u])continue;
fa[v] = u;
dfs(v);
st[++ amt][0] = u;
}
}
int ask_LCA(int p, int q) {
p = pos[p], q = pos[q];
if(p > q)swap(p, q);
int len = lg[q - p + 1];
return Min(st[p][len], st[q-(1<<len)+1][len]);
}
int dist(int x, int y) { return dep[x] + dep[y] - 2 * dep[ask_LCA(x, y)]; }
//------------------------------------------------------------------------------------//
int Mx, Sum, G, g[MAXN], size[MAXN];
double sum[MAXN], sp[MAXN], spp[MAXN], ppdd[MAXN], pdd[MAXN], ppd[MAXN], p[MAXN];
double _sum[MAXN], _sp[MAXN], _spp[MAXN], _ppdd[MAXN], _pdd[MAXN], _ppd[MAXN];
bool vis[MAXN];
void getg(int u, int fa) {
int f = 0;
size[u] = 1;
for(int i = h[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to;
if(v == fa || vis[v]) continue;
getg(v, u);
size[u] += size[v];
f = max(f, size[v]);
}
f = max(f, Sum - size[u]);
if(f < Mx) {
Mx = f, G = u;
}
}
void work(int u, int f, int st) {
int dis = dist(st, u);
sp[st] += p[u];
spp[st] += p[u] * p[u];
sum[st] += p[u] * dis;
pdd[st] += p[u] * dis * dis;
ppd[st] += p[u] * p[u] * dis;
ppdd[st] += p[u] * p[u] * dis * dis;
for(int i = h[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to;
if(v == f || vis[v]) continue;
work(v, u, st);
}
}
void work2(int u, int f, int st) {
int dis = dist(g[st], u);
_sp[st] += p[u];
_spp[st] += p[u] * p[u];
_sum[st] += p[u] * dis;
_pdd[st] += p[u] * dis * dis;
_ppd[st] += p[u] * p[u] * dis;
_ppdd[st] += p[u] * p[u] * dis * dis;
for(int i = h[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to;
if(v == f || vis[v]) continue;
work2(v, u, st);
}
}
void solve(int u, int f) {
g[u] = f;
vis[u] = true;
work(u, 0, u);
if(f)work2(u, 0, u);
for(int i = h[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to;
if(vis[v]) continue;
Mx = inf, Sum = size[v], G = v;
getg(v, u), solve(G, u);
}
}
//------------------------------------------------------------------------------------//
int Standard;
double Filp(int u, double x) { return p[u] * (1-x) + (1-p[u]) * x; }
double sqr(double x) { return x * x; }
void modify(int x, double w, double s) {
int dis = dist(x, Standard);
sp[x] += w;
spp[x] += s;
sum[x] += w * dis;
ppd[x] += s * dis;
pdd[x] += w * dis * dis;
ppdd[x] += s * dis * dis;
if(g[x] == 0) return;
dis = dist(g[x], Standard);
_sp[x] += w;
_spp[x] += s;
_sum[x] += w * dis;
_ppd[x] += s * dis;
_pdd[x] += w * dis * dis;
_ppdd[x] += s * dis * dis;
modify(g[x], w, s);
}
typedef pair<double, double> pii;
pii ask(int x) {
double dis = dist(x, Standard);
double ret1 = sum[x]+dis*sp[x], ret2 = -(ppdd[x] + 2*ppd[x]*dis + spp[x]*sqr(dis)) + pdd[x] + 2*sum[x]*dis + sp[x]*sqr(dis);
if(g[x] == 0) return make_pair(ret1, ret2);
dis = dist(g[x], Standard);
ret1 -= _sum[x]+dis*_sp[x], ret2 -= -(_ppdd[x] + 2*_ppd[x]*dis + _spp[x]*sqr(dis)) + _pdd[x] + 2*_sum[x]*dis + _sp[x]*sqr(dis);
pii t = ask(g[x]);
ret1 += t.first, ret2 += t.second;
return make_pair(ret1, ret2);
}
int main() {
freopen("network.in", "r", stdin);
freopen("network.out", "w", stdout);
scanf("%d", &n);
scanf("%d%d", &n, &m);
for(int i = 1 ; i <= n ; ++ i)
scanf("%d", &c[i]), p[i] = c[i];
int u, v, w;
for(int i = 1 ; i < n ; ++ i) {
scanf("%d%d", &u, &v);
addedge(u, v);
}
dfs(1);
lg[0] = -1;
for(int i = 1 ; i <= amt ; ++ i)
lg[i] = lg[i>>1] + 1;
for(int j = 1 ; 1<<j <= amt ; ++ j)
for(int i = 1 ; i+(1<<j)-1 <= amt ; ++ i)
st[i][j] = Min(st[i][j-1], st[i+(1<<j-1)][j-1]);
Mx = inf, Sum = n;
getg(1, 0);
solve(G, 0);
int tp;
for(int i = 1; i <= m ; ++ i) {
scanf("%d", &tp);
if(tp == 1) {
scanf("%d%d", &u, &w);
double t = w / 100.0, k = Filp(u, t);
Standard = u;
modify(u, k-p[u], -p[u]*p[u]+k*k);
p[u] = k;
} else {
scanf("%d", &u);
Standard = u;
pii t = ask(u) ;
printf("%.10lf\n", sqr(t.first) + t.second);
}
}
return 0;
}
[Day4 2016-7-4]
T1:exercise
f[n] = (a*f[n-1] + b) / (c*f[n-1] + d) mod p
对于每组f0, n, a, b, c, d, p(p 是质数),求fn。
保证除法时逆元一定存在。
暴力搞出相邻三项的式子,发现它的系数是
|A C|
|B D|
这个矩阵的平方
然后快速幂就好了。。
#include <cstdio>
using namespace std;
typedef long long ll;
int a, b, c, d, f0, md;
ll n;
struct Matrix {
int a[2][2];
void clr() { a[0][0] = a[0][1] = a[1][0] = a[1][1] = 0; }
void set() { clr(); a[0][0] = a[1][1] = 1; }
}nw, ret;
Matrix operator * (const Matrix& a, const Matrix& b) {
Matrix c;
for(int i = 0 ; i < 2 ; ++ i)
for(int j = 0 ; j < 2 ; ++ j)
c.a[i][j] = ((ll)a.a[i][0]*b.a[0][j] + (ll)a.a[i][1]*b.a[1][j]) % md;
return c;
}
ll power_mod(ll a, ll b) {
ll ret = 1;
while(b > 0) {
if(b & 1) ret = ret * a % md;
b >>= 1;
a = a * a % md;
} return ret;
}
int solve() {
nw.a[0][0] = a, nw.a[1][0] = b;
nw.a[0][1] = c, nw.a[1][1] = d;
ret.set();
while(n > 0) {
if(n & 1) ret = ret * nw;
n >>= 1;
nw = nw * nw;
}
ll f = ((ll)f0 * ret.a[0][0] + ret.a[1][0]) % md;
ll g = ((ll)f0 * ret.a[0][1] + ret.a[1][1]) % md;
f = (ll) f * power_mod(g, md-2) % md;
return f;
}
int main() {
freopen("exercise.in", "r", stdin);
freopen("exercise.out", "w", stdout);
int test;
scanf("%d", &test);
while(test --) {
scanf("%d%d%d%d%d%lld%d", &f0, &a, &b, &c, &d, &n, &md);
if(a < 0) a += md; if(b < 0) b += md;
if(c < 0) c += md; if(d < 0) d += md;
printf("%d\n", solve());
}
return 0;
}
T2:mountain
pty爬山
求爬过的节点数目
题解在2013年论文集
#define MAXN 1000010
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
struct Point { int x, y, i; };
Point operator - (const Point& a, const Point& b) { return (Point){a.x-b.x, a.y-b.y}; }
ll operator ^ (const Point& a, const Point& b) { return (ll)a.x*b.y-(ll)a.y*b.x; }
Point a[MAXN], lw[MAXN], rw[MAXN], h[MAXN];
int n, fa[MAXN], tot, Lt[MAXN], Rt[MAXN], tmp[MAXN];
ll f[MAXN];
struct arr {
int v, t;
bool operator < (const arr& k) const {
return v < k.v || (v == k.v && (t&1) < (k.t&1)) || (v == k.v && (t&1) == (k.t&1) && t < k.t);
}
}p[MAXN];
ll abs(ll x) { return x > 0 ? x : -x; }
void init() {
scanf("%d", &n);
for(int i = 1 ; i <= n ; ++ i)
scanf("%d%d", &a[i].x, &a[i].y), a[i].i = i;
}
void find(int u) {
tot = 0;
while(fa[u]) tmp[++ tot] = u, u = fa[u];
for(int i = tot ; i >= 1 ; -- i) {
int u = tmp[i];
f[u] = f[fa[u]] + abs(fa[u]-u);
fa[u] = 0;
} return;
}
void make_ans() {
for(int i = 1 ; i <= n ; ++ i)
if(fa[i]) find(i);
for(int i = 1 ; i <= n ; ++ i)
printf("%lld\n", f[i]);
}
void work() {
tot = 0;
for(int i = 1 ; i <= n ; ++ i) {
while(tot > 0 && ((h[tot]-h[tot-1])^(a[i]-h[tot-1])) >= 0) tot --;
lw[i] = h[tot];
if(i == 1 || a[i].y >= lw[i].y) lw[i] = a[i];
h[++ tot] = a[i];
}
tot = 0;
for(int i = n ; i >= 1 ; -- i){
while(tot > 1 && ((h[tot]-h[tot-1])^(a[i]-h[tot-1])) <= 0) tot --;
rw[i] = h[tot];
if(i == n || a[i].y > rw[i].y) rw[i] = a[i];
h[++ tot] = a[i];
}
for(int i = 1 ; i <= n ; ++ i) {
if(lw[i].y > rw[i].y) p[i].v = lw[i].y, p[i].t = i<<1;
else p[i].v = rw[i].y, p[i].t = i<<1|1;
}
sort(p+1, p+1+n);
for(int i = 1 ; i <= n ; ++ i)
Lt[i] = i-1, Rt[i] = i+1;
for(int i = 1 ; i <= n ; ++ i) {
int j = p[i].t >> 1;
if(p[i].t & 1) fa[j] = Rt[j];
else fa[j] = Lt[j];
Rt[Lt[j]] = Rt[j];
Lt[Rt[j]] = Lt[j];
} fa[p[n].t>>1] = 0;
make_ans();
}
int main() {
freopen("mountain.in", "r", stdin);
freopen("mountain.out", "w", stdout);
init();
work();
return 0;
}

r,c<=n,m<=1000. k <= n*m
神题。。把平方拆开还有一个矩阵与矩阵的乘法
用二维卷积
#define MAXN 1010
#define MAXM 2200000
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
typedef long double ld;
const ld pi = 3.1415926535897932384626433832795;
const int md = 998244353, G = 3;
struct Point { ll val; int i, j; };
bool operator < (const Point& a, const Point& b) {
if(a.val != b.val)return a.val < b.val;
if(a.i != b.i) return a.i < b.i;
return a.j < b.j;
}
/*
struct cpx { ld r, i; };
cpx operator + (const cpx& a, const cpx& b) { return (cpx){a.r+b.r, a.i+b.i}; }
cpx operator - (const cpx& a, const cpx& b) { return (cpx){a.r-b.r, a.i-b.i}; }
cpx operator * (const cpx& a, const cpx& b) { return (cpx){a.r*b.r-a.i*b.i, a.r*b.i+a.i*b.r}; }
cpx operator / (const cpx& a, const ld& k) { return (cpx){a.r/k, a.i/k}; }
cpx f[MAXM], g[MAXM];
void fft(cpx A[], int n, int tp) {
for(int i = 0, j = 0 ; i < n ; ++ i) {
if(i > j) swap(A[i], A[j]);
for(int t = n>>1 ; (j^=t) < t ; t >>= 1);
}
for(int k = 2 ; k <= n ; k <<= 1) {
int t = k>>1;
cpx wn = (cpx){cos(2*pi/k), tp*sin(2*pi/k)};
for(int i = 0 ; i < n ; i += k) {
cpx w = (cpx){1, 0};
for(int j = 0 ; j < t ; ++ j) {
cpx T = w * A[i+j+t];
A[i+j+t] = A[i+j] - T;
A[i+j] = A[i+j] + T;
w = w * wn;
}
}
}
if(tp == -1) {
for(int i = 0 ; i < n ; ++ i)
A[i] = A[i] / n;
}
}
*/
int f[MAXM], g[MAXM];
Point nw[MAXM];
int n, m, r, c, A[MAXN][MAXN], B[MAXN][MAXN], C[MAXN][MAXN];
ll s[MAXN][MAXN], SA[MAXN][MAXN], SB, S[MAXN][MAXN], Sb;
ll sqr(ll a) { return a * a; }
ll square_SA(int x1, int y1, int x2, int y2) {
x1 --, y1 --;
ll ret = SA[x2][y2];
if(x1 >= 0) ret -= SA[x1][y2];
if(y1 >= 0) ret -= SA[x2][y1];
if(x1 >= 0 && y1 >= 0) ret += SA[x1][y1];
return ret;
}
ll square_S(int x1, int y1, int x2, int y2) {
x1 --, y1 --;
ll ret = S[x2][y2];
if(x1 >= 0) ret -= S[x1][y2];
if(y1 >= 0) ret -= S[x2][y1];
if(x1 >= 0 && y1 >= 0) ret += S[x1][y1];
return ret;
}
int power_mod(int a, int b = md-2) {
int ret = 1;
while(b > 0) {
if(b & 1)ret = (ll)ret * a % md;
b >>= 1;
a = (ll)a * a % md;
} return ret;
}
void ntt(int A[], int n, int tp) {
for(int i = 0 ; i < n ; ++ i) if(A[i] < 0) A[i] += md;
for(int i = 0, j = 0 ; i < n ; ++ i) {
if(i > j) swap(A[i], A[j]);
for(int t = n>>1 ; (j^=t) < t ; t >>= 1);
}
for(int k = 2 ; k <= n ; k <<= 1) {
int t = k>>1;
int wn = power_mod(G, tp > 0 ? (md-1)/k : (md-1)-(md-1)/k);
for(int i = 0 ; i < n ; i += k) {
int w = 1;
for(int j = 0 ; j < t ; ++ j) {
int T = (ll)w * A[i+j+t] % md;
A[i+j+t] = A[i+j] - T; if(A[i+j+t]<0) A[i+j+t] += md;
A[i+j] = A[i+j] + T; if(A[i+j] >= md) A[i+j] -= md;
w = (ll)w * wn % md;
}
}
}
if(tp == -1) {
ll inv = power_mod(n);
for(int i = 0 ; i < n ; ++ i) {
A[i] = (ll)A[i] * inv % md;
if(A[i] < 0) A[i] += md;
}
}
}
int main() {
freopen("matrix.in", "r", stdin);
freopen("matrix.out", "w", stdout);
scanf("%d%d", &n, &m);
for(int i = 0 ; i < n ; ++ i)
for(int j = 0 ; j < m ; ++ j)
scanf("%d", &A[i][j]);
scanf("%d%d", &r, &c);
for(int i = 0 ; i < r ; ++ i)
for(int j = 0 ; j < c ; ++ j)
scanf("%d", &C[i][j]);
for(int i = 0 ; i < n ; ++ i)
for(int j = 0 ; j < m ; ++ j)
B[i][j] = C[n-i-1][m-j-1];
/*
int cnt = 0, N;
for(int i = 0 ; i < n ; ++ i)
for(int j = 0 ; j < m ; ++ j)
f[cnt ++] = (cpx){A[i][j], 0};
cnt = 0;
for(int i = 0 ; i < n ; ++ i)
for(int j = 0 ; j < m ; ++ j)
g[cnt ++] = (cpx){B[i][j], 0};
for(N = 1 ; N <= cnt+cnt ; N <<= 1);
fft(f, N, 1);
fft(g, N, 1);
for(int i = 0 ; i < N ; ++ i)
f[i] = f[i] * g[i];
fft(f, N, -1);
*/
int cnt = 0, N;
for(int i = 0 ; i < n ; ++ i)
for(int j = 0 ; j < m ; ++ j)
f[cnt ++] = A[i][j];
cnt = 0;
for(int i = 0 ; i < n ; ++ i)
for(int j = 0 ; j < m ; ++ j)
g[cnt ++] = B[i][j];
for(N = 1 ; N <= cnt+cnt ; N <<= 1);
ntt(f, N, 1);
ntt(g, N, 1);
for(int i = 0 ; i < N ; ++ i)
f[i] = (ll)f[i] * g[i] % md;
ntt(f, N, -1);
int inf = 30*1000*1000;
for(int i = 0 ; i < n ; ++ i)
for(int j = 0 ; j < m ; ++ j) {
s[i][j] = f[n*m+i*m+j-1];
if(s[i][j] > inf) s[i][j] -= md;
}
int dx, dy, k;
scanf("%d%d%d", &dx, &dy, &k);
S[0][0] = A[0][0];
SA[0][0] = sqr(A[0][0]);
for(int i = 1 ; i < n ; ++ i) {
S[i][0] = S[i-1][0] + A[i][0];
SA[i][0] = SA[i-1][0] + sqr(A[i][0]);
}
for(int i = 1 ; i < m ; ++ i) {
S[0][i] = S[0][i-1] + A[0][i];
SA[0][i] = SA[0][i-1] + sqr(A[0][i]);
}
for(int i = 1 ; i < n ; ++ i)
for(int j = 1 ; j < m ; ++ j) {
S[i][j] = S[i][j-1] + S[i-1][j] - S[i-1][j-1] + A[i][j];
SA[i][j] = SA[i][j-1] + SA[i-1][j] - SA[i-1][j-1] + sqr(A[i][j]);
}
for(int i = 0 ; i < r ; ++ i)
for(int j = 0 ; j < c ; ++ j)
SB += sqr(C[i][j]), Sb += C[i][j];
int num = r * c; cnt = 0;
for(int i = 0 ; i <= n-r ; ++ i)
for(int j = 0 ; j <= m-c ; ++ j) {
int to = A[i+dx-1][j+dy-1];
nw[++ cnt] = (Point){square_SA(i, j, i+r-1, j+c-1) + SB + num*sqr(to) - 2*s[i][j] - 2*square_S(i, j, i+r-1, j+c-1)*to + 2*Sb*to, i+1, j+1};
}
sort(nw+1, nw+1+cnt);
for(int i = 1 ; i <= k ; ++ i)
printf("%d %d %lld\n", nw[i].i, nw[i].j, nw[i].val);
return 0;
}
[2016-7-16] 存在了网易网盘集训交流文件夹下
1.snow
太沙茶了竟然写错了链表。。
挺好的一道题,很多神犇都用线段树写的
我写了堆+线段树+链表
#define MAXN 300010
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
int m, n, pre[MAXN], nxt[MAXN], f[MAXN];
struct Seg { int l, r; } p[MAXN], ret1, ret2, tmp;
bool operator < (const Seg& a, const Seg& b) {
return a.l < b.l;
}
bool cmp(int i, int j) { return p[i].l < p[j].l; }
struct Node{ int len, l, r, id; } nw;
bool operator < (const Node& a, const Node& b) {
if(a.len != b.len)return a.len > b.len;
return a.id > b.id;
}
priority_queue<Node> q;
bool vis[MAXN];
int mx[MAXN<<2], mn[MAXN<<2];
#define lc id<<1
#define rc id<<1|1
void build(int id, int l, int r) {
if(l == r) {
mn[id] = p[l].l;
mx[id] = p[l].r;
return;
}
int mid = l + r >> 1;
build(lc, l, mid);
build(rc, mid+1, r);
mn[id] = mn[lc];
mx[id] = mx[rc];
}
void pushdown(int id) {
mn[lc] = max(mn[lc], mn[id]);
mx[lc] = min(mx[lc], mx[id]);
mn[rc] = max(mn[rc], mn[id]);
mx[rc] = min(mx[rc], mx[id]);
}
void upd1(int id, int l, int r, int p, int v) {
if(r <= p) {
mx[id] = min(mx[id], v);
return;
}
pushdown(id);
int mid = l + r >> 1;
if(p <= mid) upd1(lc, l, mid, p, v);
else {
mx[lc] = min(mx[lc], v);
upd1(rc, mid+1, r, p, v);
}
}
void upd2(int id, int l, int r, int p, int v) {
if(l >= p) {
mn[id] = max(mn[id], v);
return;
}
pushdown(id);
int mid = l + r >> 1;
if(p <= mid) {
mn[rc] = max(mn[rc], v);
upd2(lc, l, mid, p, v);
}
else upd2(rc, mid+1, r, p, v);
}
Seg ask(int id, int l, int r, int p) {
if(l == r) return (Seg){mn[id], mx[id]};
pushdown(id);
int mid = l + r >> 1;
if(p <= mid) return ask(lc, l, mid, p);
else return ask(rc, mid+1, r, p);
}
void Delete() {
if(nw.id != 1) upd1(1, 1, n, nw.id-1, nw.l);
if(nw.id != n) upd2(1, 1, n, nw.id+1, nw.r);
int pr = pre[nw.id], nt = nxt[nw.id];
if(nt) pre[nt] = pr, ret2 = ask(1, 1, n, nt);
if(pr) {
nxt[pr] = nt, ret1 = ask(1, 1, n, pr);
while(pre[pr]) {
tmp = ask(1, 1, n, pre[pr]);
if(tmp.l == ret1.l && tmp.r == ret1.r) {
// q.push((Node){ret1.r-ret1.l, ret1.l, ret1.r, pr});
pr = pre[pr], ret1 = tmp;
}
else break;
}
}
if(!pr && !nt) return;
if(pr && nt) {
q.push((Node){ret1.r-ret1.l, ret1.l, ret1.r, pr});
q.push((Node){ret2.r-ret2.l, ret2.l, ret2.r, nt});
}
else if(pr) q.push((Node){ret1.r-ret1.l, ret1.l, ret1.r, pr});
else if(nt) q.push((Node){ret2.r-ret2.l, ret2.l, ret2.r, nt});
}
int main() {
freopen("snow.in", "r", stdin);
freopen("snow.out", "w", stdout);
scanf("%d%d", &m, &n);
for(int i = 1; i <= n; ++ i) {
scanf("%d%d", &p[i].l, &p[i].r);
f[i] = i;
}
sort(f+1, f+1+n, cmp);
for(int i = 1; i <= n; ++ i)
pre[i] = i-1, nxt[i] = i+1;
nxt[n] = 0;
sort(p+1, p+1+n);
build(1, 1, n);
for(int i = 1; i <= n; ++ i)
q.push((Node){p[i].r-p[i].l, p[i].l, p[i].r, i});
while(!q.empty()) {
nw = q.top(); q.pop();
if(vis[nw.id]) continue;
vis[nw.id] = true;
printf("%d\n", f[nw.id]);
Delete();
} return 0;
}

浙公网安备 33010602011771号