• Codeforces Round #196 (Div. 1) 题解


      (CF唯一不好的地方就是时差……不过还好没去考,考的话就等着滚回Div. 2了……)

      A - Quiz

      裸的贪心,不过要用矩阵乘法优化或者直接推通式然后快速幂。不过本傻叉做的时候脑子一片混乱,导致WA+TLE若干次,而且还做了很久(半小时)……

    #include <cstdio>
    const int MOD = 1000000000+9;
    int ans,n,m,k;
    int power(long long x,int k)
    {
    	int res = 1;
    	for (;k;k >>= 1,x = x*x%MOD)
    		if (k&1) res = 1ll*res*x%MOD;
    	return res;
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("A.in","r",stdin);
    	freopen("A.out","w",stdout);
    	#endif
    	scanf("%d%d%d",&n,&m,&k);
    	long long i;
    	// for (i = 0; 1; i += k) {
    	// 	if (n - i <= m) break;
    	// 	if (m >= k - 1) {
    	// 		m -= (k - 1);
    	// 		(ans += k - 1)%=MOD;
    	// 	}else {
    	// 		(ans += m)%=MOD;
    	// 		printf("%d
    ",ans);
    	// 		return 0;
    	// 	}
    	// }
    	i = 1ll*(n - m)*k;
    	//printf("%d
    ",i);
    	if (i > n) {
    		printf("%d
    ",m);
    		return 0;
    	}
    	ans = 1ll*(n - m)*(k - 1)%MOD;
    	int ans1 = 0;
    	//for (; i + k <= n; i += k) ans1 = (ans1 + k)%MOD*2%MOD;
    	ans1 = (1ll*k*(power(2,(n - i)/k + 1) - 2 + MOD))%MOD;
    	//printf("%d
    ",ans1);
    	(ans1 += MOD)%=MOD;
    	i = (n -i)/k * k + i;
    	(ans1 += n - i)%=MOD;
    	printf("%d
    ",(ans + ans1)%MOD);
    }
    

      

      B - Book of Evil

      一开始看错题目了……其实这题很水……只要求出每个点离它自己最远的damaged的点,最后再一个一个点枚举过去,判断过去即可。

      

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    const int N = 100000 + 9;
    int n,m,p[N],d,son[N],ec,fa[N];
    struct Edge{int link,next;}es[N*2];
    struct node{int dis,v;}f[N],g[N];
    inline void addedge(const int x,const int y)
    {
    	es[++ec].link = y;
    	es[ec].next = son[x];
    	son[x] = ec;
    }
    inline void Addedge(const int x,const int y)
    {addedge(x,y);addedge(y,x);}
    inline void update(const int u,node x)
    {
    	if (x.dis == -1) return;
    	++x.dis;
    	if (f[u].dis < x.dis) g[u] = f[u],f[u] = x;
    	else if (g[u].dis < x.dis) g[u] = x;
    }
    void dfs(const int root)
    {
    	static int son1[N];
    	memcpy(son1,son,sizeof son);
    	for (int u = root; u;) {
    		if (son[u]) {
    			const int v = es[son[u]].link;
    			son[u] = es[son[u]].next;
    			if (v == fa[u]) continue;
    			fa[v] = u;
    			u = v;
    			continue;
    		}
    		update(fa[u],f[u]);
    		u = fa[u];
    	}
    	for (int u = root; u;) {
    		if (son1[u]) {
    			const int v = es[son1[u]].link;
    			son1[u] = es[son1[u]].next;
    			if (v == fa[u]) continue;
    			fa[v] = u;
    			if (f[u].v == f[v].v) update(v,g[u]);
    			else update(v,f[u]);
    			u = v;
    			continue;
    		}
    		u = fa[u];
    	}
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("B.in","r",stdin);
    	freopen("B.out","w",stdout);
    	#endif
    	scanf("%d%d%d",&n,&m,&d);
    	memset(f, -1, sizeof f);
    	memset(g, -1, sizeof g);
    	for (int i = 1,x; i <= m; ++i) {
    		scanf("%d",&x);
    		f[x].dis = 0;
    		f[x].v = x;
    	}
    	for (int i = 1,x,y; i < n; ++i) {
    		scanf("%d%d",&x,&y);
    		Addedge(x,y);
    	}
    	dfs(1);
    	int ans = 0;
    	for (int i = 1; i <= n; ++i) if (f[i].dis <= d) ++ans;
    	printf("%d
    ",ans);
    }
    

      

      C - Divisor Tree

      这题有点意思。观察后不难得出除了root和leave以外的点都是所给的数,而root也有可能是。关键是接下来怎么弄……方法应该有很多。不过我想不出好的方法……

      于是去OrzTutorial。其实这个做法挺暴力的……是O(N!)。由于每个所给的数的father也是所给的数或root,并且比它本身来得大。于是我们可以给a[i]排序,然后枚举树的形态。注意细节处理。

    #include <cstdio>
    #include <algorithm>
    const int N = 9;
    int ans = 0x7fffffff,n,pnum[N],cnt;
    long long a[N],root;
    inline void getpnum()
    {
    	for (int i = 1; i <= n; ++i) {
    		long long x = a[i];
    		for (long long j = 2; j*j <= x; ++j) 
    			for (;x % j == 0;x /= j) ++pnum[i];
    		if (x != 1) ++pnum[i];
    	}
    }
    void dfs2(const int idx,const int sum)
    {
    	if (idx == 0) {ans = std::min(ans,sum + n + 1);return;}
    	for (int i = n; i > idx; --i) {
    		if (a[i] % a[idx] == 0) {
    			a[i] /= a[idx];
    			dfs2(idx - 1,sum);
    			a[i] *= a[idx];
    		}
    	}
    	dfs2(idx - 1,sum + pnum[idx]);
    }
    bool dfs1(const int idx)
    {
    	if (idx == 0) {ans = pnum[n] + n;return 1;}
    	for (int i = n; i > idx; --i) {
    		if (a[i] % a[idx] == 0) {
    			a[i] /= a[idx];
    			if (dfs1(idx - 1)) {
    				a[i] = a[i]*a[idx];
    				return 1;
    			}
    			a[i] = a[i]*a[idx];
    		}
    	}
    	return 0;
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("C.in","r",stdin);
    	freopen("C.out","w",stdout);
    	#endif
    	scanf("%d",&n);
    	for (int i = 1; i <= n; ++i) scanf("%I64d", a + i);
    	std::sort(a + 1,a + 1 + n);
    	root = a[n];
    	getpnum();
    	for (int i = 1; i <= n; ++i) if (pnum[i] == 1) ++cnt;
    	//memcpy(back,a,sizeof a);
    	if (!dfs1(n - 1))
    		dfs2(n,0);
    	printf("%d
    ",ans - cnt);
    }
    

        

      D - GCD Table

      这题有点坑……一开始想复杂了。其实:

      gcd(i,j) = a[idx] ===> a[idx] | i a[idx] | j

      就是这样,仅此而已。

      然后可以证明row = lcm(a[1], a[2], a[3], ... ,a[n])

      证明也很简单。

        首先lcm * x (x > 0)肯定可以。只需考虑gcd(lcm,j) != gcd(lcm * x,j)的情况。

        令gcd(lcm * x,j) = d。则d | j, d 不整除 lcm。

        若这个位置是合法的话,则有a[i] = d 不整除 lcm。这明显是矛盾的。

      对于col:

        col = - k + 1 (mod a[k]) 

      然后解线性同余方程组,对答案check即可。

      Postscript: 注意乘法的地方,会爆long long。所以用类似快速幂的方法处理。

      附图一张(描述了大家被这个trick坑的惨状……)

      

      

    //greater than max_long_long ... so use quick_multiply (qmult)!
    #include <cstdio>
    #include <cmath>
    const int N = 10000 + 9;
    typedef long long ll;
    ll n,m,a[N],K;
    struct Triple
    {
    	ll x,y,z;
    	Triple(const ll _x,const ll _y,const ll _z):
    		x(_x),y(_y),z(_z){}
    };
    Triple exgcd(const ll a,const ll b)
    {
    	//  Ax1 + By1 = ax  + by
    	//  A = b, B = a % b
    	//  b * x1 + (a - a/b*b) * y1 = a * x + b * y
    	//  a*y1 + b*(x1 - a/b*y1) = a*x + b*y
    	//  x = y1, y = x1 - a/b*y1
    	if (!b) return Triple(1,0,a);
    	Triple last(exgcd(b,a%b));
    	return Triple(last.y,last.x - a/b * last.y,last.z);
    }
    ll gcd(ll a,ll b)
    {
    	for (ll t;b;)
    		t = a,a = b,b = t % b;
    	return a;
    }
    bool calc_row()
    {
    	ll last = 1;
    	for (int i = 1; i <= K; ++i) {
    		ll tmp = gcd(last,a[i]);
    		if (last / tmp > n / a[i]) return false;
    		last = last / tmp * a[i];
    	}
    	return true;
    }
    ll qmult(ll x,ll k,const ll mod)
    {
    	ll res = 0,t = 1;
    	if (k < 0) t = -1,k = -k;
    	for (;k;k >>= 1,x = x*2%mod)
    		if (k&1) res = (res + x) % mod;
    	return res*t;
    }
    bool calc_col()
    {
    	// j = -k (mod a[k + 1])
    	// x = k1 (mod a1) <=> x = a1*p1 + k1
    	// x = k2 (mod a2) <=> x = a2*p2 + k2
    	// x = a1*p1 + k1 = a2*p2 + k2 <=> a1*p1 - a2*p2 = k2 - k1
    	// x = a1*p1 + k1 (mod lcm(a1,a2))
    	ll lastk = 0,lasta = a[1];
    	if (lasta + K - 1 > m) return false;
    	for (int i = 2; i <= K; ++i) {
    		ll k = (a[i] - i + 1) % a[i];
    		Triple s(exgcd(lasta, a[i]));
    		if ((k - lastk) % s.z) return false;
    		const ll mod = a[i] / s.z;
    		const ll times = (k - lastk) / s.z % mod;
    		s.x %= mod;
    		if (fabs((double)s.x * (double)times) > 1e15) s.x = (qmult(s.x,times,mod) + mod)%mod;
    		else s.x = (s.x % mod * times % mod + mod) % mod;
    		lastk += lasta * s.x;
    		lasta = lasta / s.z * a[i];
    		if ((lastk ? lastk : lasta) + K - 1 > m) return false;
    	}
    	lastk = lastk ? lastk : lasta;
    	for (int i = 1; i <= K; ++i)
    		if (gcd(lasta,lastk + i -1) != a[i]) return false;
    	return true; 
    }
    void solve()
    {
    	if (!calc_row() || !calc_col()) puts("NO");
    	else puts("YES");
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("D.in","r",stdin);
    	freopen("D.out","w",stdout);
    	#endif
    	scanf("%I64d%I64d%I64d",&n,&m,&K);
    	for (int i = 1; i <= K; ++i) scanf("%I64d",a + i);
    	solve();
    }
    

      

      E - Optimize!

      这题就比较简单了,方法有挺多的吧……我一开始想了个傻叉办法(SPlay……),麻烦得半死……

      先sort b[] (从小到大)

      令x[i] = min{j | s[i] + b[j] >= h} , y[i] = (x[idx] = i 的个数) , sum[i] = y[i] + y[i + 1] + ... + y[len]

      用各种数据结构维护之,然后如果min(len - i + 1 - sum[i]) >= 0 就给ans 加 1。 

      P.S. 注意细节处理。

    #include <cstdio>
    #include <algorithm>
    const int N = 150000 + 9;
    int a[N],min[N*4],tag[N*4],b[N],n,len,h,L,R,D;
    inline void push_up(const int idx)
    {min[idx] = std::min(min[idx * 2], min[idx * 2 + 1]);}
    inline void push_down(const int idx)
    {
    	if (!tag[idx]) return;
    	tag[idx * 2] += tag[idx]; tag[idx * 2 + 1] += tag[idx];
    	min[idx * 2] += tag[idx]; min[idx * 2 + 1] += tag[idx];
    	tag[idx] = 0;
    }
    void modify(const int idx,const int l,const int r)
    {
    	if (L <= l && r <= R) return (void)(min[idx] += D,tag[idx] += D);
    	const int mid = (l + r) / 2;
    	if (tag[idx]) push_down(idx);
    	if (L <= mid) modify(idx * 2, l, mid);
    	if (mid < R) modify(idx * 2 + 1, mid + 1, r);
    	push_up(idx);
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("E.in","r",stdin);
    	freopen("E.out","w",stdout);
    	#endif
    	scanf("%d%d%d",&n,&len,&h);
    	for (int i = 1; i <= len; ++i) {
    		scanf("%d",b + i);
    		L = R = i;
    		D = len - i + 1;
    		modify(1,1,len);
    	}
    	for (int i = 1; i <= n; ++i) {scanf("%d",a + i); a[i] = h - a[i];}
    	std::sort(b + 1, b + 1 + len);
    	int cnt = 0,ans = 0;
    	for (int i = 1; i <= len; ++i) {
    		if (a[i] > b[len]) {++cnt;continue;}
    		if (i != 1 && a[i] <= 0) continue;
    		L = 1; R = std::lower_bound(b + 1, b + 1 + len,a[i]) - b; D = -1;
    		modify(1,1,len);
    	}
    	if (!cnt && min[1] >= 0) ++ans;
    	for (int i = len + 1; i <= n; ++i) {
    		if (a[i - len] <= b[len]) {
    			L = 1; R = std::lower_bound(b + 1, b + 1 + len,a[i - len]) - b; D = 1;
    			modify(1,1,len);
    		}else --cnt;
    		
    		if (a[i - len + 1] <= 0) {
    			L = 1; R = std::lower_bound(b + 1, b + 1 + len,a[i - len + 1]) - b; D = -1;
    			modify(1,1,len);
    		}
    
    		if (a[i] > b[len]) {++cnt;continue;}
    		if (a[i] > 0) {
    			L = 1; R = std::lower_bound(b + 1, b + 1 + len,a[i]) - b; D = -1;
    			modify(1,1,len);
    		}
    		
    		if (!cnt && min[1] >= 0) ++ans;
    	}
    	printf("%d
    ",ans);
    }
    

      

  • 相关阅读:
    MybatisPlus-03
    MybatisPlus-02
    MybatisPlus_01
    卷积网络可解释性复现 | Grad-CAM | ICCV | 2017
    卷积涨点论文 | Asymmetric Convolution ACNet | ICCV | 2019
    pytorch实现 | Deformable Convolutional Networks | CVPR | 2017
    图像处理论文详解 | Deformable Convolutional Networks | CVPR | 2017
    轮廓检测论文解读 | Richer Convolutional Features for Edge Detection | CVPR | 2017
    Argo CD使用指南:如何构建一套完整的GitOps?
    Kubernetes弃用Docker后怎么办?
  • 原文地址:https://www.cnblogs.com/lazycal/p/3268393.html
Copyright © 2020-2023  润新知