zoukankan      html  css  js  c++  java
  • Codeforces Round 596 题解

    万幸的是终于碰上了一场上分好场。

    不幸的是一开始差点不会 A。

    万幸的是想了个不那么稳的结论过了 pretest。

    不幸的是罚时很高,而且慌得一比。

    万幸的是然后半个小时内把 B 和 C 码了。

    不幸的是然后就只能看着排名一点一点掉了。

    万幸的是最后 A 没被叉掉。

    不幸的是我居然没敢去叉人。

    万幸的是我就是叉了 10 个人排名也不会上涨超过 5。

    不幸的是我每掉一名都会少涨两三分。

    万幸的是我没去打隔壁的 ZR。

    不幸的是我发现这场 ZR 我一题不会,打了就会掉分……


    2A

    没仔细想,但是应该分类讨论一下 (d_a=d_b)(d_a+1=d_b)(d_a=9,d_b=1) 就行了。

    2B1 & 2B2

    没仔细想,但是感觉双指针,动态维护不同数的个数(开个 map)就行了。

    2C/1A

    先枚举要用多少个数拼成 (n)。假设当前枚举的是 (i)

    那么等价于用恰好 (i)(2) 的整数次幂拼成 (n-pi)

    有解当且仅当 (bitcnt(n-pi)le i)(n-pige i)。其中 (bitcnt) 是二进制表示中 (1) 的个数。

    我当时猜的结论是如果有解答案不会超过 (10^6)(能稳就稳)。

    搬运下官方题解:

    (n-30pge 30) 时(即 (i=30) 时满足第二个条件),那么因为 (n-30p<2^{30})(30) 是一定合法的。否则对于 (ige 30)(n-pige i) 都不可能成立。所以答案至多是 (30)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=100010;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    int n,p;
    inline int bitcnt(int x){
    	int c=0;
    	for(;x;x&=x-1) c++;
    	return c;
    }
    int main(){
    	n=read();p=read();
    	FOR(i,1,1000000){
    		if(n-p*i>=i && bitcnt(n-p*i)<=i){
    			printf("%d
    ",i);return 0;
    		}
    	}
    	puts("-1");
    }
    

    2D/1B

    把每个数质因数分解。设 (a_i=p_{i,1}^{c_{i,1}} imes p_{i,2}^{c_{i,2}} imesdots imes p_{i,l_i}^{c_{i,l_i}})。其中 (p_{i,x}) 均为质数且单调递增,(c_{i,x}) 均为正整数。

    两个数 (i,j) 合法当且仅当 (l_i=l_j)(p_{i,x}=p_{j,x})(k|(c_{i,x}+c_{j,x}))

    那么把 ((p_{i,x},c_{i,x}mod k)) 这个二元组塞到一个 vector 后面。并且查找要求的 vector 之前的出现次数。

    时间复杂度 (O(nllog n))。其中 (l)(n) 以内所有正整数的互不相同质因子个数的最大值。(n=10^5) 时,(l=6)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=100010,sq=333;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    int n,k,a[maxn];
    vector<PII> d[maxn],tmp;
    map<vector<PII>,int> cnt;
    ll ans;
    int main(){
    	n=read();k=read();
    	FOR(i,1,n) a[i]=read();
    	FOR(i,1,n){
    		int x=a[i];
    		tmp.clear();
    		FOR(j,2,sqrt(x)) if(x%j==0){
    			int cnt=0;
    			while(x%j==0) x/=j,cnt=(cnt+1)%k;
    			if(cnt) d[i].push_back(MP(j,cnt)),tmp.push_back(MP(j,k-cnt));
    		}
    		if(x>1) d[i].push_back(MP(x,1)),tmp.push_back(MP(x,k-1));
    		ans+=cnt[tmp];
    		cnt[d[i]]++;
    	}
    	printf("%lld
    ",ans);
    }
    

    2E/1C

    比较套路的一题。

    (f_{i,j,0}) 表示目前在 ((i,j)),上一步是从左边走过来的方案数。(f_{i,j,1}) 表示目前在 ((i,j)),上一步是从上面走过来的方案数。

    初始状态 (f_{1,1,0}=f_{1,1,1}=1)。答案是 (f_{n,m,0}+f_{n,m,1})。(所以要特判 (n=m=1),至于初始状态为什么是这个,看到下面就知道了)

    (f_{i,j,0}) 为例,枚举上一个是从上面走过来的点 ((i,k))。注意到 ((i,k)) 右边的石头肯定之前都没被动过。

    那么从 ((i,k)) 走到 ((i,j)) 当且仅当 ((i,k)) 右边的石头个数 (le n-j)。这样子这些石头都可以塞到 ((i,j)) 右边,否则 ((i,j)) 肯定被石头挡住。

    如果这样,(f_{i,j,0}+=f_{i,k,1})

    发现 (k) 一定是 ([l,j-1]) 这么一段,可以二分 (l) 然后用前缀和优化。当然发现随着 (j) 递增,(l) 不会变小,也可以维护一个指针。我比较懒就用了二分。

    时间复杂度 (O(nm(log n+log m))) 或者 (O(nm))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=2222,mod=1000000007;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    int n,m,f[maxn][maxn][2],rig[maxn][maxn],dn[maxn][maxn],sum1[maxn][maxn],sum2[maxn][maxn];
    char mp[maxn];
    bool bl[maxn][maxn];
    int main(){
    	n=read();m=read();
    	if(n==1 && m==1) return puts("1"),0;
    	FOR(i,1,n){
    		scanf("%s",mp+1);
    		FOR(j,1,m) if(mp[j]=='R') bl[i][j]=true;
    	}
    	f[1][1][0]=f[1][1][1]=sum1[1][1]=sum2[1][1]=1;
    	FOR(i,1,n) ROF(j,m,1) rig[i][j]=rig[i][j+1]+bl[i][j+1];
    	ROF(i,n,1) FOR(j,1,m) dn[i][j]=dn[i+1][j]+bl[i+1][j];
    	FOR(i,1,n) FOR(j,1,m){
    		if(i==1 && j==1) continue;
    		int l=0,r=j;
    		while(l<r){
    			int mid=(l+r)>>1;
    			if(rig[i][mid]<=m-j) r=mid;
    			else l=mid+1;
    		}
    		if(l<j) f[i][j][0]=(f[i][j][0]+(sum1[i][j-1]-(l==0?0:sum1[i][l-1])+mod)%mod)%mod;	
    		l=0;r=i;
    		while(l<r){
    			int mid=(l+r)>>1;
    			if(dn[mid][j]<=n-i) r=mid;
    			else l=mid+1;
    		}
    		if(l<i) f[i][j][1]=(f[i][j][1]+(sum2[i-1][j]-(l==0?0:sum2[l-1][j])+mod)%mod)%mod;
    		sum1[i][j]=(sum1[i][j-1]+f[i][j][1])%mod;
    		sum2[i][j]=(sum2[i-1][j]+f[i][j][0])%mod;
    //		printf("f[%d][%d]=%d
    ",i,j,(f[i][j][0]+f[i][j][1])%mod);
    	}
    	printf("%d
    ",(f[n][m][0]+f[n][m][1])%mod);
    }
    

    2F/1D

    神仙题,这种构造永远想不到……

    考虑逆操作,把一个点的兄弟变成它的父亲。

    首先答案肯定不小于 ((n-1)-maxdep)。因为每次操作树的最大深度最多增加 (1)

    然后发现一定可以构造一个方案使得答案就是 ((n-1)-maxdep)。具体操作方法:找到一条从根开始的最长路径,找到上面随意一个有多个儿子的点 (v),取它在这条路径上的儿子 (u) 和任意另一个儿子 (w),把 (w) 变成 (u) 的父亲。可以发现最长路径一定变长了 (1)

    具体实现,每次取满足条件的最深的 (u)(注意,不是 (v))。可以发现每次操作之后,新的 (u) 一定是原来的 (u) 或者它的祖先。

    时间复杂度 (O(nlog n))。可以做到 (O(n)),但是好像很难写。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100010,mod=998244353;
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline int read(){
    	int x=0,f=0;char ch=getchar();
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    int n,fa[maxn],dep[maxn],last=1,chg,ans[maxn],al,seq[maxn],sl;
    set<int> s[maxn];
    int main(){
    	n=read();
    	FOR(i,2,n){
    		dep[i]=dep[fa[i]=read()+1]+1;
    		s[fa[i]].insert(i);
    		if(dep[i]>dep[last]) last=i;
    	}
    	chg=last;
    	while(chg!=1){
    		while(chg!=1 && s[fa[chg]].size()==1) chg=fa[chg];
    		if(chg!=1){
    			int was=fa[chg];
    			set<int>::iterator hhh=s[was].find(chg);
    			for(set<int>::iterator it=s[was].begin();it!=s[was].end();it++){
    				int f=*it;
    				if(f==chg) continue;
    				s[f].insert(chg);
    				fa[chg]=f;
    				ans[++al]=chg-1;
    				s[was].erase(hhh);
    				break;
    			}
    		}
    	}
    	for(int i=last;i;i=fa[i]) seq[++sl]=i-1;
    	ROF(i,n,1) printf("%d ",seq[i]);
    	printf("
    %d
    ",al);
    	ROF(i,al,1) printf("%d ",ans[i]);
    }
    

    1E & 1F

    这些都不会,咕了。

  • 相关阅读:
    location.href使用方法总结
    Ubuntu 12.04 安装JDK 8和Eclipse
    【一】仿微信飞机大战cocos2d-x3.0rc1
    QTP的基本功能介绍
    Spring+Ibatis集成开发实例
    Java NIO与IO的差别和比較
    嵌入式Linux常见问题
    递归和迭代之间的差
    大约sources.list和apt-get [转载]
    JVM学习笔记(一)------的基本结构
  • 原文地址:https://www.cnblogs.com/1000Suns/p/11746670.html
Copyright © 2011-2022 走看看