• Codeforces Round #506 (Div. 3) 题解及训练总结


    这场可能是因为stl和kmp用的熟,并且前段时间遇到过一道跟取余有关系的题给了思路比较接近,所以abcd都秒了。e题有思路,但是写不出来,f回头想了下觉得挺简单的。四题过后对应rank可以到前30。
    总结:

    1. 犯了一个错误1e9的长度当成了9
    2. nex数组初始值nex0=-1,这个不太熟练,浪费了几分钟
    3. e题没有沉下头写
    4. f题没有多想

    题解
    A
    题意:给你一个字符串s,求怎样构造出一个字付串t,使他的子串包含k个s。求最短的t(s长度和k<50)
    思路:考虑前缀和后缀最长相同长度。可以暴力,也可以kmp nex数组。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    const int maxn = 1e4+5;
    int nex[maxn];
     
    void getnex(string s){
    	int n = s.size(),i = 0,j = -1;
    	nex[0] = -1;
    	while(i<n){
    		if(s[i]==s[j]||j==-1) nex[++i] = ++j;
    		else j = nex[j];
    		//cerr<<i<<' '<<j<<'
    ';
    	}
    }
     
    int main(){
    	IO;
    	int n,k;cin>>n>>k;
    	string s;cin>>s;
    	getnex(s);
    	//cerr<<"!@3"<<'
    ';
    	int pos = nex[n];
    	string t = s;
    	k--;
    	//cerr<<"!@3"<<'
    ';
    	while(k--){
    		for(int i = pos;i<n;i++) t+=s[i];
    	}
    	cout <<t<<'
    ';
     
     
     
     
     
    	return 0;
    }
    

    B.
    题意:给你一个长度n(2e5)的递增数组,让你找一个子串,它的2*ai>=ai+1。
    思路:On的跑一遍,满足条件cnt++,此外cnt=0。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
     
    int main(){
    	IO;
    	int n;cin>>n;
    	vector<int>a(n);
    	forn(i,n)  cin>>a[i];
    	int cnt = 1,ans = 1;
    	for1(i,n-1){
    		if(a[i]<=a[i-1]*2) cnt++;
    		else cnt = 1;
    		ans = max(ans,cnt);
    	}
    	cout << ans <<'
    ';
    	return 0;
    }
    

    C
    题意:给你n(2e5)个区间,让你删掉一个区间,使得区间重合部分最大。
    思路:用multiset
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
     
    int main(){
    	IO;
    	int n;cin>>n;
    	vector<pair<int,int> >a(n);
    	multiset<int>l,r;
    	forn(i,n){
    		cin>>a[i].first>>a[i].second;
    		l.insert(a[i].first);
    		r.insert(a[i].second);
    	}
    	int ans = 0;
    	forn(i,n){
    		l.erase(l.find(a[i].first));
    		r.erase(r.find(a[i].second));
    		int x = *l.rbegin(),y = *r.begin();
    		ans = max(ans,y-x);
    		l.insert(a[i].first);
    		r.insert(a[i].second);	
    	}
    	cout << ans <<'
    ';
    	return 0;
    }
    

    D
    题意:给你n个数(2e5),和一个k(1e9)。现在让你将任意两个数组合,比如12和23可以组合成1223和2312,如果组合过的数可以整除k,那么算是一个好数。看有多少个好数。
    思路:很显然一个组合有数x10^leny
    和y组成,那么只要知道x
    10^leny的余数和y的余数相加是否为0或k就可以。
    预处理每个数字*10^(1-10)的余数,然后对应加起来。坑点比较多。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll unsigned long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
     
    map<ll,int>b[15];
     
    int main(){
    	IO;
    	int n,k;cin>>n>>k;vector<int>a(n);
    	forn(i,n){
    		cin>>a[i];
    		ll x = a[i];
    		for1(j,10){
    			x*=10;
    			x%=k;
    			b[j][x]++;
    			//cerr<<x<<' '<<y<<'
    ';
    		}
    	}
    	ll ans = 0;
    	forn(i,n){
    		int len = 0,x = a[i];
    		while(x){
    			x/=10;
    			len++;
    		}
    		x = a[i]%k;
    		int y = k-x;
    		y%=k;
    		ans+=b[len][y];
    		ll z = a[i];
    		while(len--){
    			z*=10;
    			z%=k;
    		}
    		x = z%k;
    		if(x==y) ans--;
    	}
    	cout << ans <<'
    ';
    	return 0;
    }
    

    E
    题意:给一棵树,n个点,n-1条边每个边权值为1。现在添加k条边使得所有点与1点距离小于等于2,求k的最小值。(n1e5)
    思路:贪心 每次取距离1点最长距离点的父亲节点与1相连。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll unsigned long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    const int maxn = 2e5+5;
    int ans;
    vector<int>e[maxn],dis(maxn);
     
    int dfs(int u,int pre,int d){
    	dis[u] = d;
    	bool ok = 0;
    	for(auto x:e[u]){
    		if(x==pre) continue;
    		dfs(x,u,d+1);
    		if(dis[x]>2){
    			ok = 1;
    			dis[u] = 1;
    			dis[pre] = 2;
    		}
    	}
    	ans+=ok;
    }
     
    int main(){
    	IO;
    	int n;cin>>n;
    	forn(i,n-1){
    		int x,y;cin>>x>>y;
    		e[x].push_back(y);
    		e[y].push_back(x);
    	}
    	dfs(1,1,0);
    	for1(i,4)cerr<<dis[i]<<' ';
    	cerr<<'
    ';
    	cout << ans<<'
    ';
    	
    	
    	
    	return 0;
    }
    

    F
    题意:给你a个红色砖块和b个蓝色砖块,要求用完a和b拼成一个长方形(可以是正方形),并且满足里面的仅由红色砖或蓝色砖可组成一个矩形。求此矩形的最小周长。
    思路:根号下枚举a,b和大矩形的宽。通过大矩形宽来找a或b中满足条件的最大宽(logn可以优化为On),然后记录一次ans,取最小。在来找最大宽的时候,我们可以根据上一次的结论来确定的新的最大宽为多少。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(ll i=0;i<n;i++)
    #define for1(i,n) for(ll i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
     
    int main(){
    	IO;
    	ll a,b;cin>>a>>b;		
    	ll n = sqrt(a),m = sqrt(b);
    	vector<int>aa,bb;
    	for1(i,n)if(a%i==0) aa.push_back(i); 
    	for1(i,m)if(b%i==0) bb.push_back(i);
    	ll sum = a+b;int x = sqrt(sum);
    	ll ans = 0x3f3f3f3f3f3f3f3f;
    	int p1,p2;p1 = p2 = 0;
    	for1(h,x)if(sum%h==0){
    		ll w = sum/h;
    		while(p1<aa.size()&&aa[p1]<=h)p1++;
    		while(p2<bb.size()&&bb[p2]<=h)p2++;
    		if(p1&&a/aa[p1-1]<=w) ans = min(ans,2*(h+w));
    		if(p2&&b/bb[p2-1]<=w) ans = min(ans,2*(h+w));
    	}
    	cout << ans<<'
    ';
    	return 0;
    }
    
    人一我百,人十我万。
  • 相关阅读:
    [ASM/C/C++]内存碎片处理技术
    NASM网际编译器手册(三)
    NASM网际编译器手册(四)
    NASM网际编译器手册(六)
    NASM网际编译器手册(一)
    IEEE浮点数表示法
    设计模式学习每日一记(12.轻量模式)
    设计模式学习每日一记(11.代理模式)
    canvas一句话备忘录
    usaco1.1.1PROB Your Ride Is Here
  • 原文地址:https://www.cnblogs.com/AlexPanda/p/12520323.html
Copyright © 2020-2023  润新知