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;
}

  

posted @ 2016-07-01 15:29  _Horizon  阅读(144)  评论(0)    收藏  举报