• 20190907 模拟赛题解


    T1

    题意

    给出NN,求形如(a,b,c,d)(a,b,c,d)的有序数对使得a+b+c+d=Na+b+c+d=Na,b,c,da,b,c,d均为质数。
    N100000Nle 100000

    题解

    考场上我就写了FFTFFT,然后过掉了。

    然后发现100000100000内的质数大概只有95009500个,然后加起来的和100000le100000的质数对是可以枚举的。所以直接先预处理每个数等于两个质数加起来的方案,然后枚举前两个数的和xx,乘上NxN-x等于后两个数的和的方案,最后全部加起来就是了。

    放上FFTFFT的代码

    CODE

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long double ld;
    typedef double db;
    const int MAXN = 100005;
    const db Pi = acos(-1.0);
    int p[MAXN/10], cnt;
    bool vis[MAXN];
    void pre(int N) {
    	for(int i = 2; i <= N; ++i) {
    		if(!vis[i]) p[++cnt] = i;
    		for(int j = 1; j <= cnt && i*p[j] <= N; ++j) {
    			vis[i*p[j]] = 1;
    			if(i % p[j] == 0) break;
    		}
    	}
    }
    const int MAXL = (1<<18)+5;
    struct cp {
    	db x, y;
    	cp(){}
    	cp(db x, db y):x(x), y(y){}
    	inline cp operator +(const cp &o)const { return cp(x+o.x, y+o.y); }
    	inline cp operator -(const cp &o)const { return cp(x-o.x, y-o.y); }
    	inline cp operator *(const cp &o)const { return cp(x*o.x - y*o.y, x*o.y + o.x*y); }
    }f[MAXL], tmp[2][19][MAXL/2];
    int rv[MAXL];
    
    inline void FFT(cp* arr, const int &n, const int &flg) {
    	for(register int i = 0; i < n; ++i) if(i < rv[i]) swap(arr[i], arr[rv[i]]);
    	static cp t;
    	for(register int i = 2, p = 1; i <= n; i<<=1, ++p) {
    		for(register int j = 0; j < n; j+=i) {
    			for(register int k = j, q = 0; k < j+i/2; ++k, ++q) {
    				t = arr[k + i/2] * tmp[flg][p][q];
    				arr[k + i/2] = arr[k] - t;
    				arr[k] = arr[k] + t;
    			}
    		}
    	}
    	if(!flg) for(register int i = 0; i < n; ++i) arr[i].x /= n;
    }
    int nn[15];
    int main () {
    	freopen("plus.in", "r", stdin);
    	freopen("plus.out", "w", stdout);
    	int n = 0, T;
    	scanf("%d", &T);
    	for(int i = 1; i <= T; ++i)
    		scanf("%d", &nn[i]), n = max(n, nn[i]);
    	pre(n);
    	for(int i = 1; i <= cnt; ++i) f[p[i]] = cp(1, 0);
    	int len = 1; while(len <= (n<<1)) len<<=1;
    	for(int i = 1; i < len; ++i) 
    		rv[i] = (rv[i>>1]>>1)|((i&1)*(len>>1));
    	for(int i = 1; i <= 18; ++i) {
    		cp w1 = cp(cos(2*Pi/(1<<i)), sin(2*Pi/(1<<i)));
    		cp w0 = cp(cos(-2*Pi/(1<<i)), sin(-2*Pi/(1<<i)));
    		tmp[1][i][0] = tmp[0][i][0] = cp(1, 0);
    		for(int j = 1; j <= (1<<17); ++j)
    			tmp[1][i][j] = tmp[1][i][j-1] * w1,
    			tmp[0][i][j] = tmp[0][i][j-1] * w0;
    	}
    	FFT(f, len, 1);
    	for(int i = 0; i < len; ++i) f[i] = f[i] * f[i];
    	FFT(f, len, 0);
    	for(int i = 1; i <= n; ++i) f[i] = cp(round(f[i].x), 0);
    	for(int i = n+1; i < len; ++i) f[i] = cp(0, 0);
    	
    	FFT(f, len, 1);
    	for(int i = 0; i < len; ++i) f[i] = f[i] * f[i];
    	FFT(f, len, 0);
    	
    	for(int i = 1; i <= T; ++i)
    		printf("%lld
    ", (long long)(round(f[nn[i]].x)));
    }
    

    T2

    题意

    假设给定了两个整数 m,nm,n。有 nn 个互不相同的整数 x1,x2,...,xn(0xi2m1)x1,x2,...,xn(0≤xi≤2^m-1)。对于每一个属于 002m12^m-1 的 y,我们找到 pyp_y使得 xpyx_{p_y}异或 yy 有最大值。即对于任意的 i≠pyi= ot p_y,有 yxpy&gt;yxiy⊕x_{p_y} &gt;y⊕ x_i。(其中表示二进制异或)。

    现在我们把这个问题反过来。给定 mmnn,以及序列 p0,p1,...,p2m1p_0,p_1,...,p_{2^m-1},计算有多少个不同序列 x1,x2,...,xnx_1,x_2,...,x_n 可以通过上文描述的问题生成出序列 pp。两个序列是不同的当且仅当存在一个 i 使得两个序列中 xix_i是不同的。

    答案对 1000000007(109+7)1000000007(10^9+7)取模。
    m16,n2mmle16,nle 2^m

    题解

    考虑分治。对于区间(l,r)(l,r)的所有pp考虑,这里的pl...rp_{l...r}都要在(l,r)(l,r)范围内。

    假设xx序列中既有最高位为00的数,又有最高位为11的数。那么(l,mid)(l,mid)pp(mid+1,r)(mid+1,r)pp一定没有交集。因为他们的pp都是在对方的区间取得。那么就可以分治下去。方案就是(l,mid)(l,mid)(mid+1,r)(mid+1,r)的答案乘起来。

    另一种情况是xx序列中只有最高位为00的或者只有最高位为11的数。那么两边的pp一定是一一对应的。因为所有的xix_i最高位是一样的,不用考虑。所以由于一一对应,答案就是(l,mid)2(l,mid)*2,因为最高位既可以是00又可以是11。这种情况的条件是p(l,mid)=p(mid+1,r)p(l,mid)=p(mid+1,r),顺次一一相等。

    边界就是l=rl=r时返回11。因为相当于m=0m=0,下面的数只有一个选择。

    考试时差点想到…没有发现第二种情况两边的pp一一对应。

    CODE

    #include <cstdio>
    const int mod = 1e9 + 7;
    const int MAXN = (1<<16)+5;
    int n, m, s, p[MAXN]; bool vis[MAXN];
    int solve(int l, int r) {
    	if(l == r) return 1;
    	int mid = (l + r) >> 1, re = 0;
    	bool flg = 1;
    	for(int i = l; i <= mid; ++i)
    		if(p[i] != p[mid+i-l+1]) { flg = 0; break; }
    	if(flg) re = (re + 2ll * solve(l, mid) % mod) % mod;
    	
    	flg = 1;
    	for(int i = l; i <= mid; ++i) vis[p[i]] = 1;
    	for(int i = mid+1; i <= r; ++i) if(vis[p[i]]) { flg = 0; break; }
    	for(int i = l; i <= mid; ++i) vis[p[i]] = 0;
    	if(flg) re = (re + 1ll * solve(l, mid) * solve(mid+1, r) % mod) % mod;
    	
    	return re;
    }
    int main () {
    	freopen("match.in", "r", stdin);
    	freopen("match.out", "w", stdout);
    	scanf("%d%d", &m, &n);
    	s = 1<<m;
    	for(int i = 1; i <= s; ++i) scanf("%d", &p[i]);
    	printf("%d
    ", solve(1, s));
    }
    

    T3

    题意

    一棵树,初始时所有边都是黑色。有两种操作:

    • 00:求aabb路径上的黑边数量。
    • 11:将aabb路径上所有边设为白边,然后把只有一个点在这条路径上的边设为黑边。

    题解

    以为写了8080分暴力,发现有3030的数据不符合题目描述(可能是题目描述不符合数据? ),然后就5050了…

    正解比较巧妙,我们把11操作看做把aba o b所有点染上一个新的颜色,一条边为白边当且仅当两个点颜色相同。然后我们树剖后只需要维护线段上不同颜色段数就行了。

    CODE

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int MAXN = 200005;
    const int MAXQ = 300005;
    int n, fir[MAXN], to[MAXN<<1], nxt[MAXN<<1], cnt;
    inline void link(int u, int v) {
    	to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
    	to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt;
    }
    int fa[MAXN], dep[MAXN], son[MAXN], top[MAXN], dfn[MAXN], sz[MAXN];
    int tmr;
    void dfs1(int u, int ff) {
    	dep[u] = dep[fa[u]=ff] + (sz[u]=1);
    	for(int i = fir[u], v; i; i = nxt[i])
    		if((v=to[i]) != ff) {
    			dfs1(v, u), sz[u] += sz[v];
    			if(sz[v] > sz[son[u]]) son[u] = v;
    		}
    }
    void dfs2(int u, int tp) {
    	top[u] = tp;
    	dfn[u] = ++tmr;
    	if(son[u]) dfs2(son[u], tp);
    	for(int i = fir[u], v; i; i = nxt[i])
    		if((v=to[i]) != fa[u] && v != son[u])
    			dfs2(v, v);
    }
    struct seg {
    	int l, r, ans;
    	seg(){}
    	seg(int l, int r, int ans):l(l), r(r), ans(ans){}
    	inline seg operator !() const{
    		return seg(r, l, ans);
    	}
    	inline seg operator +(const seg &o)const {
    		if(!ans) return o;
    		if(!o.ans) return *this;
    		return (r^o.l) ? seg(l, o.r, ans + o.ans) : seg(l, o.r, ans + o.ans - 1);
    	}
    }v[MAXN<<2];
    int lz[MAXN<<2], now;
    inline void upd(int i) { v[i] = v[i<<1] + v[i<<1|1]; }
    inline void pd(int i) {
    	if(~lz[i]) {
    		lz[i<<1] = lz[i<<1|1] = lz[i];
    		v[i<<1] = v[i<<1|1] = seg(lz[i], lz[i], 1);
    		lz[i] = -1;
    	}
    }
    void build(int i, int l, int r) {
    	lz[i] = -1;
    	if(l == r) { v[i] = seg(l, l, 1); return; }
    	int mid = (l + r) >> 1;
    	build(i<<1, l, mid);
    	build(i<<1|1, mid+1, r);
    	upd(i);
    }
    void modify(int i, int l, int r, int x, int y, int z) {
    	if(x <= l && r <= y) { v[i] = seg(z, z, 1); lz[i] = z; return; }
    	pd(i);
    	int mid = (l + r) >> 1;
    	if(x <= mid) modify(i<<1, l, mid, x, y, z);
    	if(y > mid) modify(i<<1|1, mid+1, r, x, y, z);
    	upd(i);
    }
    seg query(int i, int l, int r, int x, int y) {
    	if(x <= l && r <= y) { return v[i]; }
    	pd(i);
    	int mid = (l + r) >> 1; seg re = seg(-1, -1, 0);
    	if(x <= mid) re = re + query(i<<1, l, mid, x, y);
    	if(y > mid) re = re + query(i<<1|1, mid+1, r, x, y);
    	upd(i);
    	return re;
    }
    inline void cover(int a, int b) {
    	++now;
    	while(top[a]^top[b]) {
    		if(dep[top[a]] > dep[top[b]]) modify(1, 1, n, dfn[top[a]], dfn[a], now), a = fa[top[a]];
    		else modify(1, 1, n, dfn[top[b]], dfn[b], now), b = fa[top[b]];
    	}
    	if(dep[a] > dep[b]) modify(1, 1, n, dfn[b], dfn[a], now);
    	else modify(1, 1, n, dfn[a], dfn[b], now);
    }
    inline int getans(int a, int b) {
    	seg L = seg(-1, -1, 0), R = seg(-1, -1, 0);
    	while(top[a]^top[b]) {
    		if(dep[top[a]] > dep[top[b]]) L = L + !query(1, 1, n, dfn[top[a]], dfn[a]), a = fa[top[a]];
    		else R = query(1, 1, n, dfn[top[b]], dfn[b]) + R, b = fa[top[b]];
    	}
    	if(dep[a] > dep[b]) L = L + !query(1, 1, n, dfn[b], dfn[a]) + R;
    	else L = L + query(1, 1, n, dfn[a], dfn[b]) + R;
    	return L.ans-1;
    }
    int main () {
    	freopen("colour.in", "r", stdin);
    	freopen("colour.out", "w", stdout);
    	scanf("%d", &n); now = n;
    	for(int i = 1, x, y; i < n; ++i)
    		scanf("%d%d", &x, &y), link(x, y);
    	dfs1(1, 0), dfs2(1, 1);
    	build(1, 1, n);
    	int q, op, a, b;
    	scanf("%d", &q);
    	while(q-->0) {
    		scanf("%d%d%d", &op, &a, &b);
    		if(op == 0) printf("%d
    ", getans(a, b));
    		else cover(a, b);
    	}
    }
    
  • 相关阅读:
    nginx 报错 upstream timed out (110: Connection timed out)解决方案
    mysql 数据库缓存调优之解决The total number of locks exceeds the lock table size错误
    阿里云ECS主机内核调优
    安装Python3.6.x
    CentOS 下 LNMP 环境配置
    Walle代码发布系统
    Ansible 运维自动化 ( 配置管理工具 )
    Kafka消息的时间戳
    Linux内存分析
    H3C 查看路由器的硬件信息
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039238.html
Copyright © 2020-2023  润新知