zoukankan      html  css  js  c++  java
  • SDOI 2018二轮题解(除Day2T1)

    博主诈尸啦

    虽然一轮之后就退役了但是二轮还是要去划划水呀~

    然鹅学了不到一个月文化课再回来看OI的东西有一种恍如隔世的感觉,烤前感觉也没啥可复习的,就补一补去年二轮的题吧。

    题目思路基本都参考自shadowice神仙Orz

    Day2T1没时间做了咕咕咕

    物理实验

    充满毒瘤气息的计算几何题。。

    首先旋转一下坐标系,那么只需要考虑两条线平行于(y)轴的情况。

    由于题目中规定每个挡板都不和直线导轨接触,因此一定是分别分布于(y > 0)(y < 0)两部分,我们分别维护。

    现在只考虑上半部分,不难看出对于两条线段一上一下的情况,上面的线段被遮挡的部分是没有用的。同时所有的线段我们可以拆成加入和删除两个事件,首先预处理出两个事件之间的最大的sec,同时有了距离就可以算出答案。

    然后双指针扫一下。

    复杂度(O(n log n))

    #include<bits/stdc++.h> 
    #define fi first
    #define se second
    #define LL long long
    #define pb push_back
    #define double long double   
    using namespace std;
    const int MAXN = 1e6 + 10;
    template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    };
    int N, opt[MAXN];
    double x[MAXN][2], y[MAXN][2], pos[MAXN], bx, by, ex, ey, L;
    double nx, val[MAXN], sec[MAXN];
    struct Segment {
        int id;
        bool operator < (const Segment &rhs) const {
            if(id == rhs.id) return 0;
            int td = rhs.id;
            double va = (y[id][1] - y[id][0]) / (x[id][1] - x[id][0]) * (nx - x[id][0]) + y[id][0];
            double vb = (y[td][1] - y[td][0]) / (x[td][1] - x[td][0]) * (nx - x[td][0]) + y[td][0];
            return abs(va) < abs(vb);
        }
    };
    set<Segment> su, sd;
    double GouGu(double x, double y) {
        return sqrt(x * x + y * y);
    }
    int comp(int a, int b) {
        return (a < 0 ? x[-a][1] : x[a][0]) < (b < 0 ? x[-b][1] : x[b][0]);
    }
    void init() {
        nx = 0; memset(val, 0, sizeof(val));
    }
    void solve() {
        N = read();
        init();
        for(int i = 1; i <= N; i++) {
            x[i][0] = read(); y[i][0] = read(); x[i][1] = read(); y[i][1] = read();
        }
        bx = read(), by = read(); ex = read(); ey = read(); L = read();
        double dx = ex - bx, dy = ey - by, dis = GouGu(dx, dy);
        double bl = (bx == by) ? 0 : by - dy / dx * bx;
        for(int i = 1; i <= N; i++) y[i][0] -= bl, y[i][1] -= bl;
        dx /= dis; dy /= dis;//dx cos dy sin
        //(x, y) 
        for(int i = 1; i <= N; i++) {
            double px1 = x[i][0], px2 = x[i][1], py1 = y[i][0], py2 = y[i][1];
            x[i][0] = dx * px1 + dy * py1; //tag
            y[i][0] = dx * py1 - dy * px1;
            x[i][1] = dx * px2 + dy * py2;
            y[i][1] = dx * py2 - dy * px2;
            if(x[i][0] > x[i][1]) swap(x[i][0], x[i][1]), swap(y[i][0], y[i][1]);
            sec[i] = GouGu(x[i][1] - x[i][0], y[i][1] - y[i][0]) / (x[i][1] - x[i][0]);
        }
        for(int i = 1; i <= 2 * N; i++) opt[i] = (i <= N ? -i : i - N);
        sort(opt + 1, opt + 2 * N + 1, comp);
        for(int i = 1; i <= 2 * N; i++) {
            int u;
            if(opt[i] > 0) {//insert
                u = opt[i];
                nx = pos[i] = x[u][0];
                (y[u][0] > 0 ? su : sd).insert({u});
            } else {//delet
                u = -opt[i];
                nx = pos[i] = x[u][1];
                (y[u][0] > 0 ? su : sd).erase({u});
            }	
            if(!su.empty()) val[i] += sec[su.begin()->id];
            if(!sd.empty()) val[i] += sec[sd.begin()->id];
        }
        for(int i = 2 * N; i >= 1; i--) val[i] = val[i- 1];
        double ret = 0, rl = pos[1] - L, rr = pos[1], ans = 0;
        int pl = 1, pr = 2;
        while(pr <= 2 * N) {
            double dl = pos[pl] - rl, dr = pos[pr] - rr;
            if(dl > dr)      ret += (val[pr] - val[pl]) * dr, pr++, rl += dr, rr += dr;
            else if(dr > dl) ret += (val[pr] - val[pl]) * dl, pl++, rl += dl, rr += dl;
            else ret += (val[pr] - val[pl]) * dl, pr++, pl++, rl += dl, rr += dl;
            ans = max(ans, ret);
        }
        printf("%.15Lf
    ", ans);
    }
    signed main() {
        for(int T = read(); T--; solve());
        return 0;
    }
    

    战略游戏

    首先建出圆方树,那么答案为包含所有询问点的最小联通块大小 减去关键点个数

    最小联通块大小可以转化为边的贡献最后特判LCA,将所有点按dfs序排序后算出相邻两点的dis,最后/2即可

    复杂度(O(n log n))

    #include<bits/stdc++.h> 
    #define Pair pair<int, int>
    #define MP(x, y) make_pair(x, y)
    #define fi first
    #define se second
    //#define int long long 
    #define LL long long
    #define pb push_back  
    #define Fin(x) {freopen(#x".in","r",stdin);}
    #define Fout(x) {freopen(#x".out","w",stdout);}
    using namespace std;
    const int MAXN = 1e6 + 10, mod = 1e9 + 7;
    const LL INF = 1e18 + 10;
    const double eps = 1e-9;
    template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
    template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
    template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
    template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
    template <typename A> inline void debug(A a){cout << a << '
    ';}
    template <typename A> inline LL sqr(A x){return 1ll * x * x;}
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int N, M, nd;
    vector<int> v[MAXN], E[MAXN];
    int dfn[MAXN], low[MAXN], times, st[MAXN], tp;
    void tarjan(int x, int fa) {
        dfn[x] = low[x] = ++times;
        st[++tp] = x;
        for(auto &to : v[x]) {
            if(to == fa) continue;
            if(!dfn[to]) {
                tarjan(to, x), chmin(low[x], low[to]);
                if(low[to] >= dfn[x]) {
                    E[++nd].pb(x); E[x].pb(nd);
                    do {
                        E[nd].pb(st[tp]); E[st[tp]].pb(nd);
                    }while(st[tp--] != to);
                }
            }
            else chmin(low[x], dfn[to]);
    
        }
    }
    int dis[MAXN], siz[MAXN], son[MAXN], top[MAXN], dep[MAXN], ffa[MAXN];
    void dfs(int x, int fa) {
        siz[x] = 1; ffa[x] = fa;
        for(auto &to : E[x]) {
            if(to == fa) continue;
            dis[to] = dis[x] + (to <= N);
            dep[to] = dep[x] + 1;
            dfs(to, x);
            siz[x] += siz[to];
            if(siz[to] > siz[son[x]]) son[x] = to;
        }
    }
    void dfs2(int x, int topf) {
        top[x] = topf; dfn[x] = ++times;
        if(!son[x]) return ;
        dfs2(son[x], topf);
        for(auto &to : E[x]) {
            if(top[to]) continue;
            dfs2(to, to);
        }
    }
    int LCA(int x, int y) {
        while(top[x] ^ top[y]) {
            if(dep[top[x]] < dep[top[y]]) swap(x, y);
            x = ffa[top[x]];
        }
        return dep[x] < dep[y] ? x : y;
    }
    int Dis(int x, int y) {
        return dis[x] + dis[y] - 2 * dis[LCA(x, y)];
    }
    int comp(int a, int b) {
        return dfn[a] < dfn[b];
    }
    void init() {
        for(int i = 1; i <= N; i++) v[i].clear();
        for(int i = 1; i <= nd; i++) E[i].clear();
    #define m0(x) memset(x, 0, sizeof(x))
        m0(top); m0(dfn); m0(low); m0(dis); m0(dep); m0(son); m0(ffa); m0(siz); m0(dis);
    #undef m0
        tp = 0; times = 0; nd = 0;
        
    }
    int ggg = 0;
    void solve() {
        N = read(); M = read();
        init();
        nd = N;
        for(int i = 1; i <= M; i++) {
            int x = read(), y = read();
            v[x].pb(y); v[y].pb(x);		
        }
        tarjan(1, 0);
        dfs(1, 0);
        dfs2(1, 1);
        int Q = read();
        for(int k = 1; k <= Q; k++) {
            int num = read(); LL ans = 0;
            vector<int> po;
            for(int i = 1; i <= num; i++) po.pb(read());
            sort(po.begin(), po.end(), comp);
            for(int i = 0; i < po.size() - 1; i++) {
                ans += Dis(po[i], po[i + 1]);
            }
            ans += Dis(po[num - 1], po[0]);
            ans = ans  / 2 + (LCA(po[0], po[num - 1]) <= N) - num;
        cout << ans << '
    ';
    
        }
    }
    
    signed main() {
        for(int T = read(); T--; solve());
        return 0;
    }
    

    反回文串

    神仙反演Orzzzzzzzzzz

    首先一个串的本质不同的轮换个数是不重叠最小循环节的长度

    如果最小循环节的长度(d)是偶数,此时一个回文串的(d)种不同的轮换字符串当中恰好有两个回文串(本身一个,把前(frac{d}{2})个字符拼到后面一个)

    否则(d)是奇数的话一定会有(d)个本质不同的字符串

    首先考虑字符集为(k)的情况下回文串的数量(g(n))

    显然(g(n) = k^{lfloorfrac{n+1}{2} floor})(固定一半)

    那么设

    [egin{cases} h(i) = &i &(i equiv 1 pmod 2)\ &frac{i}{2} &(Otherwise) end{cases} ]

    (f(i))表示最小循环节为(i)的字符串数量,显然有

    (Ans(n) = sum_{d|n} h(d) f(d))

    (f(d))很难直接求,但是我们可以枚举循环节得到一个等式

    [g(n) = sum_{d|n} f(d) ]

    反演一下

    [f(n) = sum_{d|n} mu(d) g(frac{n}{d}) ]

    带入原来的公式

    [Ans(n) = sum_{d|n} h(d) sum_{k |d} mu(k) g(frac{d}{k}) ]

    我们尝试枚举(g)

    [Ans(n) = sum_{k|n} g(k) sum_{k|d ext{且}d|n} h(d) mu(frac{d}{k}) ]

    (d)拆为(d = d' * K),我们去枚举新的(d')

    [Ans(n) = sum_{k|n} g(k) sum_{d|frac{n}{k}} h(k d) mu(d) ]

    之前我们发现(h)函数有比较好的性质,这里似乎可以直接把(d)提出来。分析一下不难发现,只有当(d)是偶数且(k)是奇数是不能直接提。因为一个奇数不会有偶数因子,那么(frac{n}{k})一定是偶数

    此时把式子中的(k)提出来,考虑一下(ksum_{d|frac{n}{k}} h(d)mu(d))的值,打一下表可以发现值总是(0),因为(2)这个因子使得(mu)(pm 1)的项消掉了

    那么在计算这时候直接把这种情况判掉就可以

    原式变为

    [Ans(n) = sum_{k|n} g(k)h(k) sum_{d|frac{n}{k}} dmu(d) ]

    然后直接对(n)进行Pollard-Rho分解,分解的同时可以求出后面的值,拿个map存一下。

    然后dfs枚举约数直接算就行了

    复杂度玄学,但是出题人把(n)出到(10^{18})也只能这么干。。

    #include<bits/stdc++.h> 
    #define fi first
    #define se second
    #define int long long 
    #define LL long long
    #define pb push_back  
    using namespace std;
    const int MAXN = 1e6 + 10;
    const LL INF = 1e18 + 10;
    int mod;
    template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
    template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
    LL mul(LL a, LL b, int mod = mod) {
        //a %= mod, b %= mod;
        return ((a * b - (LL)((LL)((long double)a / mod * b + 1e-3) * mod)) % mod + mod) % mod;
    }
    int fp(int a, int p, int mod = mod) {
        int base = 1;
        while(p) {
            if(p & 1) base = mul(base, a, mod);
            a = mul(a, a, mod); p >>= 1;
        }
        return base;
    }
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int N, K;
    int st, ans;
    vector<int> ds;
    unordered_map<LL, LL> t, vds;
    const int Tn = 9;
    int Cbase[11] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
    bool CheckP(int p) {
        if(p == 1) return 0;
        for(int i = 0; i < Tn; i++) if(p == Cbase[i]) return 1;
        for(int id = 0; id < Tn; id++) {
            int v = Cbase[id];
            int lim = 0, t = p - 1, pre = 1;
            while(t && (!(t & 1))) lim++, t>>= 1; t = fp(v, t, p);
            while(lim--) {
                t = mul(t, t, p);
                if(t == 1 && (pre != p - 1 && pre != 1)) return 0;
                pre = t;
            }
            if(t != 1) return 0;
        }
        return 1;
    }
    
    int rnd() {
        return rand();
    }
    int gcd(int a, int b) {
        return (!b) ? a : gcd(b, a % b);
    }
    int rd(int base, int mod) {
        return (mul(base, base, mod) + st) % mod;
    }
    int myabs(int x, int y) {
        return (x > y) ? x - y : y - x;
    }
    
    void Rho(int x) {
        if(x == 1) return ;
        if(CheckP(x)) {
            vds[x]++;
            return ;
        }
        while(1) {
            st = rand() % x + 1;
            int v1 = rnd() % x + 1, g = gcd(x, v1);
            if(g != 1 && g != x) {Rho(g); Rho(x / g); return ;}
            int v2 = v1; v1 = rd(v1, x);
            for(int k = 0, tr = 1; v1 - v2; v1 = rd(v1, x), k++) {
                g = gcd(x, myabs(v1, v2));
                if(g != 1 && g != x) {Rho(g); Rho(x / g); return ;}
                if(k == tr) {v2 = v1; tr <<= 1;}
            }
        }
    }
    void Clear() {
        ds.clear();	
        vds.clear();
        ans = 0;
    }
    int g(int x) {
        return fp(K, (x + 1) / 2);
    }
    int h(int x) {
        return (x & 1) ? x : x / 2;
    }
    
    void dfs(int n, int num, int cur, unordered_map<LL, LL>::iterator now) {
        if(now == vds.end()) {
            ds.pb(num);
            t[num] = cur;
            return ;
        }
        int nn = now->se, vv = now->fi, vvd = (1 - now->fi), nv = vv, nvd = vvd; auto nxt = ++now;
        dfs(n + 1, num, cur, nxt);
        for(int i = 1; i <= nn; i++) {
            dfs(n + 1, num * nv, cur * vvd, nxt);
            nv *= vv; nvd *= vvd;
        }
    }
    void print(int x) {
        if(x > 9) print(x / 10);
        putchar('0' + x % 10);
    }
    void solve() {
        Clear();
        N = read(); K = read(); mod = read(); K %= mod;
        Rho(N);
        dfs(0, 1, 1, vds.begin());
        for(auto &num: ds) {
            if((num & 1) && (!((N / num) & 1))) continue;
            add2(ans, mul(g(num), mul(h(num), t[N / num])));	
        }
        print(ans); putchar('
    ');
    }
    signed main() {
    #ifndef ONLINE_JUDGE
        freopen("a.in", "r", stdin);
    #endif
        srand(20020113);
        for(int T = read(); T--; solve());
        return 0;
    }
    

    旧式题

    我实在不想照着题解抄一遍公式了qwq

    #include<bits/stdc++.h>
    #define Pair pair<int, int>
    #define MP make_pair
    #define fi first
    #define se second 
    #define LL long long 
    
    const int MAXN = 2e5 + 10, mod = 1e9 + 7;
    using namespace std;
    template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
    template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
    template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
    template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
    inline int read() {
    	char c = getchar(); int x = 0, f = 1;
    	while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return x * f;
    }
    int mu[MAXN], prime[MAXN], vis[MAXN], tot, A, B, C, num, deg[MAXN];
    int fa[MAXN], fb[MAXN], fc[MAXN];
    vector<LL> di[MAXN];
    vector<Pair> v[MAXN];//每个数的质因数分解 
    struct Edge {
    	LL u, v, w;
    }E[MAXN * 10];
    void GetPrime(int N) {
    	vis[1] = 1; mu[1] = 1;
    	for(int i = 2; i <= N; i++) {
    		if(!vis[i]) prime[++tot] = i, mu[i] = -1;
    		for(int j = 1; j <= tot && i * prime[j] <= N; j++) {
    			vis[i * prime[j]] = 1;
    			if(i % prime[j]) mu[i * prime[j]] = -mu[i];
    			else {mu[i * prime[j]] = 0; break;}
    		}
    	}
    	for(int i = 1; i <= tot; i++) 
    		for(int j = 1; j * prime[i] <= N; j++) 
    			di[j * prime[i]].push_back(prime[i]);
    		
    }
    
    void Get(int *a, int N, int X) {
    	for(int i = 1; i <= N; i++)
    		for(int j = i; j <= N; j += i) a[i] += X / j;
    }
    LL lcm(int a, int b) {
    	return 1ll * a / __gcd(a, b) * b;
    }
    void init() {
    	memset(fa, 0, sizeof(fa));
    	memset(fb, 0, sizeof(fb));
    	memset(fc, 0, sizeof(fc));
    	memset(deg, 0, sizeof(deg));
    	num = 0;
    	for(int i = 1; i <= A; i++) v[i].clear();
    }
    void Build() {
    	for(int w = 1; w <= A; w++) {//lcm(u, v) = w;
    		if(!mu[w]) continue;
    		int n = di[w].size();
    		//for(auto x : di[w]) printf("%d ", x); puts("");
    		for(int sta = 0; sta < (1 << n); sta++) {
    			LL i = 1;
    			for(int b = 0; b < n; b++) 
    				if(sta >> b & 1) i *= di[w][b];
    			for(int s = sta; ; s = sta & (s - 1)) {//tag
    				LL g = 1;
    				for(int b = 0; b < n; b++) 
    					if(s >> b & 1) 
    						g *= di[w][b];
    				int j = w * g / i; 
    				if(i < j) E[++num] = {i, j, w};// printf("%d
    ", num);
    				if(!s) break;
    			}
    		}
    	}
    }
    
    LL fuck(int x, int y, int w) {
    	if(mu[x] == 1) 
    		return add(add(mul(mul(fa[w], fb[w]), fc[y]), mul(mul(fa[w], fb[y]), fc[w])), mul(mul(fa[y], fb[w]), fc[w]));
    	else 
    		return (-add(add(mul(mul(fa[w], fb[w]), fc[y]), mul(mul(fa[w], fb[y]), fc[w])), mul(mul(fa[y], fb[w]), fc[w])) + mod) % mod;
    }
    
    LL calc() {
    //	for(int i = 1; i <= A; i++) for(auto &x : v[i])printf("%d %d %d
    ", i, x.fi, x.se);
    	for(int i = 1; i <= num; i++) {
    		int x = E[i].u, y = E[i].v;
    		if(deg[x] > deg[y]) swap(x, y);
    		v[y].push_back(MP(x, E[i].w));
    	}
    	LL ans = 0;
    	for(int a = 1; a <= A; a++) {
    		for(auto &t1 : v[a]) {
    			LL b = t1.fi, w1 = t1.se;
    			for(auto &t2 : v[b]) {
    				LL c = t2.fi, w2 = t2.se, xi = mu[a] * mu[b] * mu[c];
    				LL w3 = lcm(a, c);
    				if(w3 > A) continue;
    				if(xi == 1) {
    					add2(ans, mul(mul(fa[w1], fb[w2]), fc[w3]));
    					add2(ans, mul(mul(fa[w1], fb[w3]), fc[w2]));
    					add2(ans, mul(mul(fa[w2], fb[w1]), fc[w3]));
    					add2(ans, mul(mul(fa[w2], fb[w3]), fc[w1]));
    					add2(ans, mul(mul(fa[w3], fb[w1]), fc[w2]));
    					add2(ans, mul(mul(fa[w3], fb[w2]), fc[w1]));
    				} else if(xi == -1) {
    					add2(ans, mul(mul(-fa[w1], fb[w2]), fc[w3]));
    					add2(ans, mul(mul(-fa[w1], fb[w3]), fc[w2]));
    					add2(ans, mul(mul(-fa[w2], fb[w1]), fc[w3]));
    					add2(ans, mul(mul(-fa[w2], fb[w3]), fc[w1]));
    					add2(ans, mul(mul(-fa[w3], fb[w1]), fc[w2]));
    					add2(ans, mul(mul(-fa[w3], fb[w2]), fc[w1]));					
    				}
    			//	cout << ans << endl;
    			}
    		}
    	}
    
    	for(int i = 1; i <= num; i++) {//有两个一样 
    		add2(ans, fuck(E[i].u, E[i].v, E[i].w));
    		add2(ans, fuck(E[i].v, E[i].u, E[i].w));
    	}
    	for(int i = 1; i <= C; i++) {//全都一样 
    		if(mu[i] == 1) add2(ans, mul(mul(fa[i], fb[i]), fc[i]));
    		else if(mu[i] == -1) add2(ans, -mul(mul(fa[i], fb[i]), fc[i]) + mod);
    	}
    		
    	return ans;
    }
    void solve() {
    	init();
    	A = read(); B = read(); C = read();
    	if(A < B) swap(A, B); if(C > B) swap(B, C); if(A < B) swap(A, B); 
    	Get(fa, A, A); Get(fb, A, B); Get(fc, A, C);	
    	Build();
    	cout << calc() << '
    ';
    }
    signed main() {
    	GetPrime(2e5);
    	for(int T = read(); T; T--, solve());
    	return 0;
    }
    

    荣誉称号

    每个位置(x)(frac{x}{2})连边最终会得到一棵完全二叉树

    题目转化为:给出一个有点权的树,对于每个点可以花费(b_i)的代价使点权增加(1),问使得所有长度为(k + 1)的链的点权和(\% M)均为(0)的最小花费

    首先考虑序列的情况,稍加归纳后不难得到(a_i equiv a_{i + K + 1} pmod M)

    放到树上话那么最终一个点的权值一定和它的(K+1)级祖先相同,因此对于前(2^{k})个点,我们(O(nm))预处理出(w[x][y])表示(x)的点为(y)时,所有能被它限制的点的代价

    现在只需要考虑前(2^{k+1}-1)个点,首先把标号(< 2^k)的叶子节点删掉,对于剩下的点的限制条件变为所有叶子节点到根的路径和(\% M =0)。那么设(f[i][j])表示以(i)为根的子树,到所有叶子节点的权值(\%M = j)的最小代价,转移的时候暴力枚举该点的取值。

    复杂度(O(nm + 2^k m^2))可以拿到70分

    考虑(w)的预处理,std在这里用了一个等差数列,实际上不用这么麻烦,因为(a[i])取值只有(200),直接对值域暴力就行

    复杂度(O(n + 2^k m^2))

    #include<bits/stdc++.h> 
    #define Pair pair<int, int>
    #define MP(x, y) make_pair(x, y)
    #define fi first
    #define se second
    //#define int long long 
    #define LL long long
    #define pb push_back  
    #define Fin(x) {freopen(#x".in","r",stdin);}
    #define Fout(x) {freopen(#x".out","w",stdout);}
    using namespace std;
    const int MAXN = 1e7 + 10, mod = 1e9 + 7;
    const LL INF = 1e18 + 10;
    const double eps = 1e-9;
    template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
    template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
    template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
    template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
    template <typename A> inline void debug(A a){cout << a << '
    ';}
    template <typename A> inline LL sqr(A x){return 1ll * x * x;}
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int ch(int x, int l, int r) {
        return x >= l && x <= r;
    }
    int N, K, M, P, a[MAXN], mx[MAXN], n, jump, fa[MAXN], b[MAXN];
    vector<int> bel[MAXN];
    unsigned int SA, SB, SC;int p, A, B;
    unsigned int rng61(){
        SA ^= SA << 16;
        SA ^= SA >> 5;
        SA ^= SA << 1;
        unsigned int t = SA;
        SA = SB;
        SB = SC;
        SC ^= t ^ SA;
        return SC;
    }
    void gen(){
        N = read(); K = read(); M = read(); P = read(); SA = read(); SB = read(); SC = read(); A = read(); B = read();
        for(int i = 1; i <= P; i++) a[i] = read() % M, b[i] = read();
        for(int i = P + 1; i <= N; i++){
            a[i] = rng61() % A + 1;
            a[i] %= M;
            b[i] = rng61() % B + 1;
        }
    }
    
    LL w[(1 << 12) - 1][201];//w[i][j] 当i为j时,所有受i限制的点的代价 
    LL f[(1 << 12) - 1][201], num[211];
    
    void dfs(int x, int dep) {
        mx[x] = dep;
        if(dep > K + 1) bel[fa[x]].pb(x);
        int base = 2 * x;
        for(int i = 0; i <= 1; i++) {
            int to = 2 * x + i; if(to > N) continue;
            dfs(to, dep + 1);
            chmax(mx[x], mx[to]);
        }
    }
    LL get(int val, LL target, LL inc) {//在%M意义下把val变为target的最小花费 
        if(target >= val) return 1l * (target - val) * inc;
        return 1ll * ((M - val) + target) * inc;
    }
    void dfs2(int x) {
        if(x > n || mx[x] <= K) return ;
        if(x >= (1 << K)) {//叶节点 
            for(int i = 0; i < M; i++) f[x][i] = w[x][i];
            return ;
        }
        for(int i = 0; i < 2; i++) if(2 * x + i <= n) dfs2(2 * x + i);
        for(int i = 0; i < M; i++) {//与叶子节点的路径和%M = j 
            f[x][i] = INF;
            for(int j = 0; j < M; j++) {//该节点的增量
                LL sv = 0;
                for(int gg = 0; gg < 2; gg++) {
                    int to = 2 * x + gg;
                    if(to <= n) 
                    sv += f[to][(i - a[x] - j + 2 * M) % M];
                }
                chmin(f[x][i], sv + w[x][(a[x] + j) % M]);
            }
        }
    }
    
    void solve() {
        gen();
        memset(f, 0, sizeof(f));
        memset(w, 0, sizeof(w));
        jump = 1; n = (1 << (K + 1)) - 1;
        for(int i = 1; i <= K + 1; i++) jump *= 2;
        for(int i = 1; i <= N; i++) {
         bel[i].clear();
        }
    
        for(int i = 1; i <= N; i++) fa[i] = (i <= n ? i : fa[i / jump]);
        dfs(1, 1);
    
        for(int i = 1; i < (1 << (K + 1)); i++) {
            memset(num, 0, sizeof(num));
            for(auto &son: bel[i]) num[a[son]] += b[son];
            for(int j = 0; j < M; j++) {
                w[i][j] += get(a[i], j, b[i]);
                for(int k = 0; k < M; k++) w[i][j] += get(k, j, num[k]);
            }
        }
        dfs2(1);
        cout << f[1][0] << '
    ';
    }
    signed main() {
    #ifndef ONLINE_JUDGE
        freopen("title-task3.in", "r", stdin);
    #endif
        for(int T = read(); T--; solve());
        return 0;
    }
    
  • 相关阅读:
    相关博客
    读写锁
    vccode配置c++ 编译环境
    windows下内存检测工具
    定时器堆的实现的方法
    关于tcp send的再次思考
    关于一个socket在阻塞模式下是否还可以使用的实验
    windows下对socket的send和recv的超时设置,并附一个简洁明了的socket简单demo
    对于vector中高效删除中间元素的技巧
    ubuntu下后台服务的管理
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/10809479.html
Copyright © 2011-2022 走看看