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

    比赛链接:https://codeforces.com/contest/1336

    A. Linova and Kingdom

    贪心

    显然不会出现某个旅游城市的父亲是工业城市的情况(因为它俩交换一下就会有更大收益),因此最优解一定是工业城市远离根,旅游城市靠近根

    在上述情况下尝试着把一个(父亲是旅游城市的)工业城市变成旅游城市(好绕啊),会发现happiness变化量等于这个结点为根的子树大小,减去这个结点的深度

    因此让所有城市刚开始都是工业城市,把根放入优先队列中,然后每次取出happiness变化量最大的结点并将其儿子放入优先队列中

    #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 vector basic_string
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=200010; typedef long long ll;
    #define int ll
    int sz[N],dep[N];
    bool vis[N];
    vector<int> a[N];
    void dfs(int x){
    	vis[x]=1;
    	sz[x]=1;
    	for(auto p:a[x])
    	if(!vis[p]){
    		dep[p]=dep[x]+1;
    		dfs(p);
    		sz[x]+=sz[p];
    	}
    }
    int f(int x){
    	return sz[x]-dep[x];
    }
    int n,k;
    priority_queue<pair<ll,ll>> q;
    signed main(){
    	cin>>n>>k;
    	repeat(i,0,n-1){
    		int x,y; cin>>x>>y; x--,y--;
    		a[x]+=y;
    		a[y]+=x;
    	}
    	dep[0]=1;
    	dfs(0);
    	ll ans=0;
    	q.push({f(0),0});
    	fill(vis,vis+n,0);
    	repeat(i,0,n-k){
    		ans+=q.top().first;
    		int x=q.top().second; q.pop(); vis[x]=1;
    		for(auto p:a[x])
    		if(!vis[p])
    			q.push({f(p),p});
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

    B. Xenia and Colorful Gems

    目前有两种方法(群里大佬说的forforfor可能是第三种方法但是我没听懂)

    首先对三个数组a,b,c排序,然后遍历数组a,在数组b中二分查找出最接近 (a[i]) 的两个数(一个大于等于,一个小于等于)(b[j_1],b[j_2]),然后在数组c中二分查找出最接近 (dfrac{a[i]+b[j_1]}2) 的两个数 (c[k_{11}],c[k_{12}]),以及最接近 (dfrac{a[i]+b[j_2]}2) 的两个数 (c[k_{21}],c[k_{22}]),更新一下答案(这样会更新4次)。最后,把数组b和c交换一下重复上述操作

    第二种方法优雅很多,即排序后每个数组弄一个指针(指向数组头),考虑三个指针向后移动的三个答案(没有真的移动),哪个答案小就移动哪个(这才是真的移动),边跑边更新答案

    两个方法都贴出来了

    #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=200010; typedef long long ll; const ll INF=~0ull>>2;
    #define int ll
    vector<int> a,b,c;
    ll ans;
    template<typename T> T sqr(const T &x){return x*x;}
    void up(int x,int y,int z){
    	ans=min(ans,sqr(x-y)+sqr(y-z)+sqr(z-x));
    }
    void work2(int A,int B,const vector<int> &c){
    	int mid=(A+B)/2;
    	int ci=lower_bound(c.begin(),c.end(),mid)-c.begin();
    	if(ci!=(int)c.size())up(A,B,c[ci]);
    	if(ci!=0)up(A,B,c[ci-1]);
    }
    void work(int A,const vector<int> &b,const vector<int> &c){
    	int bi=lower_bound(b.begin(),b.end(),A)-b.begin();
    	if(bi!=(int)b.size())work2(A,b[bi],c);
    	if(bi!=0)work2(A,b[bi-1],c);
    }
    signed main(){
    	int T; cin>>T;
    	while(T--){
    		ans=INF*2;
    		{
    			int n1,n2,n3,x; cin>>n1>>n2>>n3;
    			a.clear(); b.clear(); c.clear();
    			repeat(i,0,n1)cin>>x,a.push_back(x);
    			repeat(i,0,n2)cin>>x,b.push_back(x);
    			repeat(i,0,n3)cin>>x,c.push_back(x);
    		}
    		sort(a.begin(),a.end());
    		sort(b.begin(),b.end());
    		sort(c.begin(),c.end());
    		repeat(i,0,a.size()){
    			work(a[i],b,c);
    			work(a[i],c,b);
    		}
    		cout<<ans<<endl;
    	}
    	return 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--)
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=200010; typedef long long ll; const ll INF=~0ull>>2;
    #define int ll
    vector<int> a,b,c;
    ll ans;
    template<typename T> T sqr(const T &x){return x*x;}
    int cal(int x,int y,int z){
    	return sqr(x-y)+sqr(y-z)+sqr(z-x);
    }
    template<typename T>
    int pcal(T x,T y,T z){
    	return cal(*x,*y,*z);
    }
    signed main(){
    	int T; cin>>T;
    	while(T--){
    		ans=INF*2;
    		{
    			int n1,n2,n3,x; cin>>n1>>n2>>n3;
    			a.clear(); b.clear(); c.clear();
    			repeat(i,0,n1)cin>>x,a.push_back(x);
    			repeat(i,0,n2)cin>>x,b.push_back(x);
    			repeat(i,0,n3)cin>>x,c.push_back(x);
    		}
    		sort(a.begin(),a.end());
    		sort(b.begin(),b.end());
    		sort(c.begin(),c.end());
    		auto p1=a.begin(),p2=b.begin(),p3=c.begin();
    		while(1){
    			int now=INF*2; auto nowp=&p1; ans=min(ans,pcal(p1,p2,p3));
    			if(p1!=a.end()-1 && pcal(p1+1,p2,p3)<now)now=pcal(p1+1,p2,p3),nowp=&p1;
    			if(p2!=b.end()-1 && pcal(p1,p2+1,p3)<now)now=pcal(p1,p2+1,p3),nowp=&p2;
    			if(p3!=c.end()-1 && pcal(p1,p2,p3+1)<now)now=pcal(p1,p2,p3+1),nowp=&p3;
    			if(now==INF*2)break;
    			(*nowp)++;
    		}
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    

    C. Kaavi and Magic Spell

    这个是区间dp,而且真的不难,不要被它的位置吓到了(我承认我被吓到了

    首先把字符串 (T) 的尾部加上特殊字符让它的长度和 (S) 相等(比 (S) 还长更好,雾),然后考虑状态转移方程

    如果我们已经生成了 (T) 的某个子串 (t),那么就可以把 (S[len(t)]) 插入 (t) 的前面或者后面,这时候要考虑是否匹配(即 (T)(t) 的前面或者后面是否等于 (S[len(t)])),方案数也随之转移

    因此 (dp[l][r]) 表示生成 (T[l..r]) 有多少方案数,就有 (dp[l,r]=dp[l+1][r] imes[是否匹配]+dp[l][r-1] imes[是否匹配])(具体懒得写了,看代码吧)

    可以自上而下的记忆化搜索,也可以自下而上的标准动规(比赛时我记忆化写炸了所以换成dp了)

    #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=3010; typedef long long ll;
    const int mod=(0?1000000007:998244353);
    #define int ll
    string s,t;
    int rec[N][N],n,final;
    signed main(){
    	cin>>s>>t; t+=string(s.size()-t.size()+1,'?');
    	n=s.size();
    	repeat(i,0,n+1)rec[i][i]=1;
    	repeat(len,1,n+1){
    		repeat(l,0,n)
    		if(l+len<=n){
    			int r=l+len; //注意注意注意这里区间是左闭右开的,即 T[l..(r-1)]
    			ll ans=0;
    			if(t[l]=='?' || s[len-1]==t[l])ans+=rec[l+1][r];
    			if(t[r-1]=='?' || s[len-1]==t[r-1])ans+=rec[l][r-1];
    			rec[l][r]=ans%mod;
    		}
    	}
    	repeat(i,0,n+1)
    	if(t[i]=='?')
    		final=(final+rec[0][i])%mod;
    	cout<<final<<endl;
    	return 0;
    }
    

    E1想假了,等官方题解出来了再更新/kk

    更:我能看懂E1的题解,但是代码根本写不来,那就不更了23333

  • 相关阅读:
    IO 单个文件的多线程拷贝
    day30 进程 同步 异步 阻塞 非阻塞 并发 并行 创建进程 守护进程 僵尸进程与孤儿进程 互斥锁
    day31 进程间通讯,线程
    d29天 上传电影练习 UDP使用 ScketServer模块
    d28 scoket套接字 struct模块
    d27网络编程
    d24 反射,元类
    d23 多态,oop中常用的内置函数 类中常用内置函数
    d22 封装 property装饰器 接口 抽象类 鸭子类型
    d21天 继承
  • 原文地址:https://www.cnblogs.com/axiomofchoice/p/12712912.html
Copyright © 2011-2022 走看看