zoukankan      html  css  js  c++  java
  • [百炼智能]hihoCoder挑战赛37 D Items(树状数组维护01背包—梦想成真!!!)

    http://hihocoder.com/contest/challenge37/problem/4

    • 考虑每次都是把一段或到另一段去。

    • 也就是说要快速找到原来段1,新的段0的位置

    • 结论:(1,0)的个数=(0,1)的个数

    • 证明:设增量是(x)(a[i])(a[(i+x)~mod~m])连边,可以发现若有((0,1)),则迟早会出现((1,0))

    • 那么只要找到不同的位置,树状数组维护hash值,每次二分lcp即可,复杂度(O(m~log^2~m))

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const ll mo = 23333333333333333ll;
    
    ll mul(ll x, ll y) {
    	ll z = (long double) x * y / mo;
    	z = x * y - z * mo;
    	if(z < 0) z += mo; else if(z >= mo) z -= mo;
    	return z;
    }
    
    const int W = 29;
    
    const int N = 3e5 + 5;
    
    ll w[N];
    int n, m, x;
    
    #define low(x) ((x) & -(x))
    
    ll f[N];
    void add(int x, ll y) {
    	x ++;
    	for(; x <= m; x += low(x)) f[x] = (f[x] + y) % mo;
    }
    ll sum(int x) {
    	x ++;
    	ll s = 0;
    	for(; x; x -= low(x)) s += f[x];
    	return (s % mo + mo) % mo;
    }
    
    int d[N], d0, a[N];
    
    int pd(int x, int y, int l, int r) {
    	if(x > l) swap(x, l), swap(y, r);
    	ll s1 = (sum(y) - sum(x - 1) + mo) % mo;
    	ll s2 = (sum(r) - sum(l - 1) + mo) % mo;
    	return mul(s1, w[l - x]) == s2;
    }
    
    int ef(int p, int q) {
    	if(p > q) swap(p, q);
    	int as = 0;
    	for(int l = 1, r = m - q; l <= r; ) {
    		int d = l + r >> 1;
    		if(pd(p, p + d - 1, q, q + d - 1)) as = d, l = d + 1; else r = d - 1;
    	}
    	return as;
    }
    
    void solve(int x, int y, int l, int r) {
    	if(x > y) return;
    	while(x <= y && l <= r) {
    		int g = ef(x, l);
    		if(x + g - 1 >= y) return;
    		d[++ d0] = l + g;
    		x += g + 1, l += g + 1;
    	}
    } 
    
    int main() {
    	scanf("%d %d", &n, &m);
    	w[0] = 1; fo(i, 1, m) w[i] = w[i - 1] * W % mo;
    	a[0] = 1; add(0, w[0]);
    	fo(ii, 1, n) {
    		scanf("%d", &x);
    		x %= m;
    		d0 = 0;
    		solve(0, m - x - 1, x, m - 1);
    		solve(m - x, m - 1, 0, x - 1);
    		fo(i, 1, d0) {
    			x = d[i];
    			if(!a[x]) {
    				a[x] = 1;
    				add(x, w[x]);
    			}
    		}
    	}
    	int Q; scanf("%d", &Q);
    	fo(ii, 1, Q) {
    		scanf("%d", &x);
    		pp("%s
    ", a[x] ? "YES" : "NO");
    	}
    }
    
  • 相关阅读:
    我爱java系列之---【微服务间的认证—Feign拦截器】
    我爱java系列之---【设置权限的三种解决方案】
    581. Shortest Unsorted Continuous Subarray
    129. Sum Root to Leaf Numbers
    513. Find Bottom Left Tree Value
    515. Find Largest Value in Each Tree Row
    155. Min Stack max stack Maxpop O(1) 操作
    painting house
    Minimum Adjustment Cost
    k Sum
  • 原文地址:https://www.cnblogs.com/coldchair/p/13038434.html
Copyright © 2011-2022 走看看