zoukankan      html  css  js  c++  java
  • [CF1362ABC,CF1361AB]Codeforces Round #647 (Div. 2)

    赛后发现C被fst了/kk
    本来能上分六十多,结果就上了十几

    CF1362A Johnny and Ancient Computer

    https://codeforces.com/problemset/problem/1362/A

    比赛的时候写麻烦了,其实还有更简单的实现方法

    inline int get(int x){
    	int ret=0;
    	ret+=x/3;x%=3;
    	ret+=x/2;x%=2;
    	ret+=x;
    	return ret;
    }
    int main(){
    //	std::printf("%d %d %d %d
    ",get(1),get(8),get(7),get(12));
    int T=read();while(T--){
    	LL a=read(),b=read();
    	int cnta=0,cntb=0,f=1;
    	while(a^b){
    		if(a>b){
    			if(a&1){
    				f=0;break;
    			}
    			a>>=1,cnta++;
    		}
    		else{
    			if(b&1){
    				f=0;break;
    			}
    			b>>=1,cntb++;
    		}
    	}
    	if(!f) std::puts("-1");
    	else std::printf("%d
    ",get(cnta)+get(cntb));
    }
    	return 0;
    }
    

    CF1362B Johnny and His Hobbies

    https://codeforces.com/problemset/problem/1362/B
    给出一个集合,选出一个最小的正整数,使得用它异或集合内的每一个数,所得所有数组成的集合与原集合相同
    (|S|le 1024,S_ile 1024)

    对于任意 (S_i)(S_ioplus k) 如果也在 (S) 中,那么 (k) 符合要求
    因为集合中的数互不相同,而两个不相同的数,异或后的结果必然不同

    所以从 (1) 开始枚举 (k),直到成立
    那么如何知道它在什么情况下一定不成立?只要比 (max S_i) 的二进制位多一位就可以
    多出来的那一位 (1),无法被异或掉(其它的数在这一位都是 (0)),也不可能等于任何原集合中的数
    为了方便直接枚举到了最大数乘二

    int t[10005],n;
    int main(){int T=read();while(T--){
    	n=read();
    	int max=0;
    	for(reg int a,i=1;i<=n;i++){
    		a=read();
    		t[a]=1;max=std::max(max,a);
    	}
    	int maxx=max*2;
    	for(reg int f,i=1;i<=maxx;i++){
    		f=1;
    		for(reg int j=0;j<=max;j++)if(t[j]&&!t[j^i]){
    			f=0;break;
    		}
    		if(f){
    			std::printf("%d
    ",i);
    			goto YES;
    		}
    	}
    	std::puts("-1");
    	YES:;
    	std::memset(t,0,sizeof t);
    }
    	return 0;
    }
    

    CF1362C Johnny and Another Rating Drop

    https://codeforces.com/problemset/problem/1362/C
    问从 (0)(n),每两个相邻的数的二进制表示中不同位数的个数和,是多少
    (nle 10^{18})

    一开始强行找了一波规律,发现并不明显
    然后打了个表,放到oeis上,发现还真有

    按照第一个公式写的,就是对于 (n=2m+1),答案是:

    [2^q+3m+sum_{kge 1}lfloorfrac{m-2^q}{2^k} floor ]

    其中,(q=lfloorlog_2 m floor),而第 (2m) 项是第 (2m+1) 项减一
    这玩意可以 (O(log n)) 来算,所以写了一发交上去pretest过了,结果第二天以看fst了/kk,并不知道为什么
    当然这个我也不会证明

    然后才发现还有一个更简单的公式,答案是

    [sum_{kge 0} lfloorfrac{n}{2^k} floor ]

    也是 (O(log n)),赛后按这个写过了

    这个还是可以稍微说明一下的,把它理解为对于每个二进制位一位一位地看
    对于第 (k) 个(从 (0) 开始编号)二进制位(位权 (2^k)),那么其对答案的贡献是 (lfloordfrac{n}{2^k} floor)
    也就是说,每 (2^k) 个数,(k) 位的数字会更改一次,对答案产生 (1) 的贡献
    比如 (k=2)

    001
    010
    011
    100 <----改变了一次
    101
    110
    111
    (1)000<------改变了一次
    

    为什么会这样应该挺好理解的,就是从 (0)(k) 为上的所有数字累加一遍,就会改变一次

    代码

    signed main(){int T=read();while(T--){
    	LL n=read(),f=0;
    	if(n==1){
    		std::puts("1");continue;
    	}
    	LL ans=0;
    	for(reg LL now,k=1;;k*=2){
    		now=n/k;
    		if(!now) break;
    		ans+=now;
    	}
    	std::printf("%lld
    ",ans);
    }
    	return 0;
    }
    

    CF1361A Johnny and Contribution

    https://codeforces.com/problemset/problem/1361/A
    一个无相图,每个点有点权,点权小于等于点数
    对于一个选择点的顺序,为每个点确定一个实际的点权为:在与他相邻的点中,没有出现过的,最小的正整数
    确定任意一种顺序,使得实际点权与给定点权相等
    (n,mle 5cdot 10^5)

    考虑什么时候一个点可以被选择,满足以下条件

    • 所有比它的点权小的权值,都在与它相邻的,已经被选的点中出现过
    • 它的点权没有在上述点的点权中出现过,如果出现过,肯定无解

    点权小的点,要么影响不到点权大的点,要么可以使得点权大的点在考虑上述条件时成立
    而点权大的点,无论如何影响不到点权小的点
    所以按点权从小到大考虑这些点,判断它们是否满足要求

    稍微说一下复杂度的事,用 exis[i] 表示点权为 (i) 的与当前点相邻,已经被选择的点(因为如果成立的话权值比他小的点都已经被选了,所以只要判权值大小就好了),是否存在
    代码中的这一句话:

    for(reg int k=1;k<t[u];k++)if(!exis[k]){f=0;break;}
    

    因为最多有与 (u) 相邻的点数个数个数组元素被标为 (1),所以最多枚举 (min(t_u, ext{与 }u ext{ 相邻的点的个数})) 次,所以复杂度是正确的

    #define N 500005
    #define M 1000005
    struct graph{
    	int fir[N],nex[M],to[M],tot;
    	inline void add(int u,int v){
    		to[++tot]=v;
    		nex[tot]=fir[u];fir[u]=tot;
    	}
    }G;
    int n,m;
    int ans[N];
    int t[N],exis[N],que[N];
    std::vector<int>ver[N];
    int main(){
    	n=read();m=read();
    	for(reg int a,b,i=1;i<=m;i++){
    		a=read();b=read();
    		G.add(a,b);G.add(b,a);
    	}
    	for(reg int i=1,a;i<=n;i++){
    		a=read();
    		ver[a].push_back(i);t[i]=a;
    	}
    	for(reg int size,i=1;i<=n;i++){
    		size=ver[i].size();
    		for(reg int u,j=0;j<size;j++){
    			u=ver[i][j];
    			que[0]=0;
    			for(reg int v,k=G.fir[u];k;k=G.nex[k]){
    				v=G.to[k];
    				if(t[v]<t[u]) exis[t[v]]=1,que[++que[0]]=t[v];
    				else if(t[v]==t[u]) return std::puts("-1"),0;
    			}
    			int f=1;
    			for(reg int k=1;k<t[u];k++)if(!exis[k]){f=0;break;}
    			for(reg int k=1;k<=que[0];k++) exis[que[k]]=0;
    			if(f) ans[++ans[0]]=u;
    			else return std::puts("-1"),0;
    		}
    	}
    	for(reg int i=1;i<=n;i++) std::printf("%d ",ans[i]);
    	return 0;
    }
    

    CF1361B Johnny and Grandmaster

    https://codeforces.com/problemset/problem/1361/B
    给你 (p)(k_i),把所有的 (p^{k_i}) 划分为两组,使这两组内的和,的差的绝对值最小。答案即这个绝对值,对 (10^9+7) 取模
    (p,n,k_ile 10^6)

    可以把一组里的数设成正的,一组里的设成负的,这样答案就是所有数的和的绝对值了
    一下就按照这样的思路来描述

    (k_i) 排个序,先选一个最大的 (p^{k_i}) 加入答案
    然后对于所有的 (k_jle k_i),从大到小去枚举,让答案减去 (p^{k_j})
    答案肯定要么把所有 (p^{k_j}) 都减完也大于零,要么在某一时刻等于零
    因为 (p^{k_i}) 放到 (k) 进制就是 ((1000cdots)_p)(或者更普遍的对于 (acdot p^{k_i}),表示为 ((a000cdots)_p)),如果当前有一个 (k_j=k_i),那一减就成 (0)
    而如果没有,那么 (k_j<k_i)(k_j) 显然不会减到负数

    那只要当前答案是 (0),就加上 (p_{k_i}),否则减就行了
    因为要取模,所以同时要维护一个模其它数的答案,只有两个答案都是 (0),才能确定答案实际上(取模之前)是 (0)

    #define mod 1000000007
    #define Mod 1000000003
    int n,p,a[1000005];
    inline int power(int a,int b,int p){
    	reg int ret=1;
    	while(b){
    		if(b&1) ret=((LL)ret*a)%p;
    		a=((LL)a*a)%p;b>>=1;
    	}
    	return ret;
    }
    int main(){int T=read();while(T--){
    	n=read();p=read();
    	for(reg int i=1;i<=n;i++) a[i]=read();
    	std::sort(a+1,a+1+n);
    	int ans1=0,ans2=0;
    	for(reg int i=n;i;i--){
    		if(!ans1&&!ans2){
    			ans1=((LL)ans1+power(p,a[i],mod))%mod;
    			ans2=((LL)ans2+power(p,a[i],Mod))%Mod;
    		}
    		else{
    			ans1=((LL)ans1-power(p,a[i],mod)+mod)%mod;
    			ans2=((LL)ans2-power(p,a[i],Mod)+Mod)%Mod;
    		}
    	}
    	std::printf("%d
    ",ans1);
    }
    	return 0;
    }
    
  • 相关阅读:
    处理客户端无法及时更新js、css
    关于JQ判断单选复选被选中
    一路风景,一路欣赏,一路有你
    Adobe Dreamweaver CC 2015新功能
    Eclipse导出APK文件报错 android lint problem
    swift2.0 计算圆面积
    zendStudio连接远程服务器报错java.net.SocketException
    IOS tableview 消除 分割线短 15 像素 ios8方法 swift版
    应用之间调用 UIApplication类的OpenURL方法
    iOS8 今日扩展
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/13052358.html
Copyright © 2011-2022 走看看