zoukankan      html  css  js  c++  java
  • Codeforces Round #647 (Div. 1) 题解 (ABC)

    https://codeforces.com/contest/1361

    A. Johnny and Contribution

    题面看不懂系列

    给定一个无向图,要求给所有点标上号(topic number)并且规则是,对于选中的那个点,它的标号为没在邻居的标号中出现的最小正整数(忽略暂时没标号的邻居)。问最终能不能让每个点的标号依次为 (t_1,t_2,...,t_n),能的话要给出标号顺序

    贪心贪心贪心,每个点按照 (t) 值从小到大进行操作即可

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=500010; typedef long long ll; const int inf=~0u>>2; 
    vector<int> a[N];
    struct node{int t,p;}w[N];
    int lab[N];
    int n,m;
    vector<int> v;
    int mex(int x){ //返回邻居中没有出现过的最小的正整数
    	v.clear();
    	for(auto p:a[x])
    	if(lab[p])
    		v.push_back(lab[p]);
    	sort(v.begin(),v.end());
    	unique(v.begin(),v.end());
    	repeat(i,0,v.size())
    	if(v[i]!=i+1)
    		return i+1;
    	return v.size()+1;
    }
    signed main(){
    	cin>>n>>m;
    	while(m--){
    		int x,y; cin>>x>>y;
    		a[x].push_back(y);
    		a[y].push_back(x);
    	}
    	repeat(i,0,n){
    		cin>>w[i].t;
    		w[i].p=i+1;
    	}
    	sort(w,w+n,[](node a,node b){return a.t<b.t;});
    	repeat(i,0,n){
    		int t=mex(w[i].p);
    		if(t!=w[i].t)
    			cout<<-1<<endl,exit(0);
    		lab[w[i].p]=w[i].t;
    	}
    	repeat(i,0,n)cout<<w[i].p<<' ';
    	return 0;
    }
    

    B. Johnny and His Hobbies

    这波啊,这波是贪心贪心贪心qwqqqqq

    第一步排除 (p=1) 的情况(直接输出 (n\%2)

    从大到小遍历 (p^{k_i}),对于某个 (p^{k_i}),如果 (difference) 大于0就减去 (p^{k_i}),否则加上。这么搞就是最优解辣

    • 当然 (difference) 这么大肯定是不能直接算的。方法可能不唯一,我就介绍我的思路。由于 (difference) 可以被好多 (p) 整除,我们把 (difference) 写成 (acdot p^b) 的形式(其中 (b) 等于当前访问的 (k_i))。然后我们发现,如果 (a) 大于1e6,或者小于 -1e6,那么后续的操作都不可能使 (a) 从正变零,或者从负变零。所以 (a) 大于 1e6 就把它赋值为 1e6,小于 -1e6 就赋值为 -1e6 就行了,这波操作可以防止 (a) 超 long long 范围
    • 至于为什么是贪心呢,因为在贪心的过程中,不可能出现加/减一个数导致 (difference) 符号改变的情况(必须经过0),所以贪,就硬贪
    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    #define fi first
    #define se second
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    typedef long long ll;
    #define int ll
    const int N=1000010; const int inf=~0u>>2; 
    const int mod=(1?1000000007:998244353); ll mul(ll a,ll b,ll m=mod){return a*b%m;} ll qpow(ll a,ll b,ll m=mod){ll ans=1; for(;b;a=mul(a,a,m),b>>=1)if(b&1)ans=mul(ans,a,m); return ans;} ll getinv(ll v,ll m=mod){return qpow(v,m-2,m);}
    int a[N];
    int T,n,p;
    int ans,dif,nowpos; //dif是题解里的a,nowpos就是题解里的b
    void move_to(int x){ //一波操作使nowpos变成x
    	(ans*=qpow(p,nowpos-x))%=mod;
    	if(dif){
    		repeat(i,0,nowpos-x){
    			dif=max(min(dif*p,N),-N);
    			if(abs(dif)==N)break;
    		}
    	}
    	nowpos=x;
    }
    void push(int x){ //处理p^x这个数,更新答案
    	move_to(x);
    	if(dif>0)ans--,dif--;
    	else ans++,dif++;
    }
    signed main(){
    	cin>>T;
    	while(T--){
    		cin>>n>>p;
    		repeat(i,0,n)
    			cin>>a[i];
    		if(p==1){cout<<n%2<<endl; continue;}
    		sort(a,a+n,greater<int>());
    		ans=dif=0; nowpos=N;
    		repeat(i,0,n)
    			push(a[i]);
    		move_to(0);
    		cout<<(ans%mod+mod)%mod<<endl;
    	}
    	return 0;
    }
    

    C. Johnny and Megan's Necklace

    我们发现答案的第一行(记作 (k)),其实只有21种情况(0到20),所以就从小到大搞一搞

    既然我们固定了 (k),那么我们就能用并查集快速算出哪些珍珠(pearl)是可以互相连接在一起的。我们把这样的珍珠集合看作顶点,把胶水(glue)看成边,那么求项链实际上就是求这个图的欧拉回路

    • 欧拉回路是否存在取决于:是否连通并且所有顶点的度为偶数
    • 求欧拉路径实际上就是求dfs退出序,要学欧拉路径的话不要看我代码学,因为我也几乎看不懂我在写些什么了
    • 那么,怎么用并查集处理哪些珍珠是可以连接的呢?一种方法是对后k位数进行排序然后相邻的进行判断。这个方法的复杂度比较大。事实上,如果对每个珍珠的二进制数进行颠倒,比如1011颠倒为 110100000...0(总共20位),这么做后只要一次排序就行了。而且并查集也不用每次都初始化,美滋滋(虽然我的代码还是2448ms,好慢啊,自带大常数)
    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    #define fi first
    #define se second
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=1000010;
    int T,n,p;
    struct DSU{
    	int a[N],sz[N];
    	void init(int n){
    		iota(a,a+n+1,0);
    		fill(sz,sz+n+1,1);
    	}
    	int fa(int x){
    		return a[x]==x?x:a[x]=fa(a[x]);
    	}
    	bool query(int x,int y){ //查找
    		return fa(x)==fa(y);
    	}
    	void join(int x,int y){ //合并
    		x=fa(x),y=fa(y);
    		if(x==y)return;
    		if(sz[x]>sz[y])swap(x,y);
    		a[x]=y;
    		sz[y]+=sz[x];
    	}
    }d,d2; //d维护了题解里的那个概念,d2维护了是否为连通图
    struct node{int x,p;}a[N];
    string s;
    
    namespace getans{
    vector<int> a[N];
    typedef pair<int,int> pii;
    vector<pii> ans;
    bool vis[N];
    void dfs(int i){ //dfs求欧拉回路
    	while(!a[i].empty()){
    		int x=a[i].back(),y=x^1,p=x/2;
    		a[i].pop_back();
    		if(vis[p])continue; vis[p]=1; 
    		dfs(d.fa(y));
    		ans.push_back({x+1,y+1});
    	}
    }
    void getans(){ //输出答案
    	repeat(i,0,n){
    		int x=i*2,y=i*2+1;
    		a[d.fa(x)].push_back(x);
    		a[d.fa(y)].push_back(y);
    	}
    	dfs(d.fa(0));
    	repeat_back(i,0,ans.size())cout<<ans[i].fi<<' '<<ans[i].se<<' ';
    }
    }
    
    signed main(){
    	cin>>n;
    	repeat(i,0,n*2){
    		cin>>a[i].x; s=bitset<20>(a[i].x).to_string();
    		reverse(s.begin(),s.end());
    		a[i].x=bitset<20>(s).to_ulong();
    		a[i].p=i;
    	}
    	d.init(n*2);
    	d2.init(n*2);
    	sort(a,a+n*2,[](node a,node b){return a.x<b.x;});
    	repeat(i,0,n)d2.join(i*2,i*2+1);
    	
    	repeat(k,0,21){
    		repeat(i,0,n*2-1){
    			if((a[i].x>>k)==(a[i+1].x>>k))
    				d.join(a[i].p,a[i+1].p),
    				d2.join(a[i].p,a[i+1].p);
    		}
    		int f=true;
    		if(d2.sz[d2.fa(0)]!=n*2)f=false;
    		repeat(i,0,n*2)
    			if(d.sz[d.fa(i)]%2==1)f=false;
    		if(f){
    			cout<<20-k<<endl;
    			getans::getans();
    			break;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    linux系统/var/log目录下的信息详解
    SQL 显示表名显示列名
    P2P平台介绍
    outlook署名最后一行没换行
    CSS3下的渐变文字效果实现
    SSH(poderosa)を使って、さくらのMySQLサーバーに接続する方法
    内网IP外网IP的关联及访问互联网原理
    自己吃的哑巴亏,怎么也要吞下去
    解决Ehcache缓存警告问题
    管理的艺术
  • 原文地址:https://www.cnblogs.com/axiomofchoice/p/13049766.html
Copyright © 2011-2022 走看看