zoukankan      html  css  js  c++  java
  • codeforces 1303 题解(完结)

    codeforces 1303 题解

    A. Erasing Zeroes

    想让字符串中的 (1) 连续,而我们能做的只有删 (0) ,则需要删去除开头以及结尾外的 所有 (0) 块。所以从头扫一遍统计开头 (0) 块,从尾扫一遍统计结尾 (0) 块,再用 (0) 的数量减去这两部分即可,可能为负所以跟 (0) 取最大值。

    时间复杂度 (O(n))

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef double db;
    #define _for(i,a,b) for(int i = (a);i < b;i ++)
    #define _rep(i,a,b) for(int i = (a);i > b;i --)
    #define INF 0x3f3f3f3f
    #define ZHUO 11100000007
    #define MOD 1000000007
    #define MIKUNUM 39
    #define pb push_back
    #define debug() printf("Miku Check OK!
    ")
    #define maxn 239
    #define X first
    #define Y second
    
    
    int main()
    {
    	ios::sync_with_stdio(false);
    	
    	int t;
    	cin >> t;
    	while(t--)
    	{
    		string s;
    		cin >> s;
    		
    		int stzero = 0, endzero = 0;
    		int zerocnt = 0;
    		_for(i,0,s.size())
    			if(s[i]=='0')
    				zerocnt ++;
    		
    		_for(i,0,s.size())
    			if(s[i]=='1')
    				break;
    			else
    				stzero ++;
    		
    		_rep(i,s.size()-1,-1)
    			if(s[i]=='1')
    				break;
    			else
    				endzero ++;
    		printf("%d
    ",max(0,zerocnt-endzero-stzero));
    	}
    	return 0;
    }
    

    B. National Project

    铺水泥,要求高质量水泥天数在 (left lceil frac{n}{2} ight ceil) 及以上,那其实我们可以假设要求 (left lceil frac{n}{2} ight ceil) 都是高质量水泥,然后和 (n) 取最大值即是答案。问题是要求 (left lceil frac{n}{2} ight ceil) 全是高质量水泥的天数怎么求?

    我们可以将 (g+b) 这个值打包成一个 组 ,因为他们是连续的。如果要求全是高质量水泥,答案至少应该包含最大可能的 组 值,然后再来一些 (g) 来凑。说的有点抽象,具体一点就是比如现在要求 (20)天 高质量水泥,(g==6,b==3) ,则 组 就是 (9) ,你至少需要 (3) 组,再来 (20-3×6=2) 个零散的 (g) 来凑就能凑够 (20) 天高质量水泥,也就是 (3×9+2=29) 天。

    特殊考虑 (n|g) 的情况即可。

    PS:样例中一百万天坏天气震撼我心。

    时间复杂度 (O(1))

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef double db;
    #define _for(i,a,b) for(int i = (a);i < b;i ++)
    #define _rep(i,a,b) for(int i = (a);i > b;i --)
    #define INF 0x3f3f3f3f
    #define ZHUO 11100000007
    #define MOD 1000000007
    #define MIKUNUM 39
    #define pb push_back
    #define debug() printf("Miku Check OK!
    ")
    #define maxn 239
    #define X first
    #define Y second
    
    ll n, g, b, rnt;
    int main()
    {
    	ios::sync_with_stdio(false);
    	int T;
    	cin >> T;
    	while(T--)
    	{
    		cin >> n >> g >> b;
    		ll tmpn = n/2 + (n&0x1);
    		ll curhaveg = tmpn/g;
    		rnt = curhaveg * (g+b);
    		if(curhaveg*g == tmpn)
    		{
    			rnt -= g+b;
    			curhaveg -= 1;
    		}
    		rnt += tmpn-curhaveg*g;
    		printf("%lld
    ",max(n,rnt));
    	}
    	return 0;
    }
    

    C. Perfect Keyboard

    我是负责图论和数据结构的所以咳咳...脑回路清奇,我们将每个字母看成一个节点,他们相邻就连边呗,啥情况输出 (NO) ?首先我们排除一下重边,然后就是如果有环肯定不行,自行证明一下吧,还有一个就是一个点的度大于等于 (3) 不行,这个也自己想一下为什么。

    我用的是并查集判环,度直接开数组 (in) 判断。最后图构建好以后找一个度为 (1) 的点 (dfs) 一下,没加到答案里的字母最后加进去就行了。为什么找一个度为 (1) 的点开始 (dfs) 一遍就好?因为这个无向图一定是一棵树,而且只能从儿子开始遍历,还是自己想一下为什么。

    杀鸡用了牛刀...勿喷

    时间复杂度主要用在判重边了,所以整体时间复杂度 为 (O(nlogn+nα(n))=O(nlogn))

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef double db;
    #define _for(i,a,b) for(int i = (a);i < b;i ++)
    #define _rep(i,a,b) for(int i = (a);i > b;i --)
    #define INF 0x3f3f3f3f
    #define ZHUO 11100000007
    #define MOD 1000000007
    #define MIKUNUM 39
    #define pb push_back
    #define debug() printf("Miku Check OK!
    ")
    #define X first
    #define Y second
    
    #define maxn 39
    #define maxe 2003 
    struct Djs
    {
    	int par[maxn];
    	int high[maxn];
    	void renew()
    	{
    		_for(i,1,maxn)
    		{
    			par[i] = i;
    			high[i] = 0;
    		}
    	}
    	int find(int x)
    	{
    		return par[x] == x ? x : par[x] = find(par[x]);
    	}
    	void unite(int x,int y)
    	{
    		x = find(x);
    		y = find(y);
    		if(x==y) return ;
    		if(high[x]<high[y])
    			par[x] = y;
    		else
    		{
    			par[y] = x;
    			if(high[x]==high[y])
    				high[x] ++;
    		}
    	}
    	bool same(int x,int y)
    	{
    		return find(x) == find(y);
    	}
    }djs;
    
    struct G
    {
        int n,m;
    	int Next[maxe];
    	int head[maxn];
    	int ver[maxe];
    	int tot;
    	void add(int x,int y)
    	{
    		ver[++tot] = y,Next[tot] = head[x],head[x] = tot;
    	}
    	void renew()
    	{
    		tot = 0;
    		n = 26;
    		memset(head,0,sizeof(head));
    	}
    } g;
    
    int to(char c)
    {
    	return c-'a'+1;
    }
    
    int vis[27];
    int in[27];
    string rnt;
    
    void dfs(int x)
    {
    	rnt += x+'a'-1;
    	vis[x] = 1;
    	for(int i = g.head[x]; i; i = g.Next[i])
    	{
    		int y = g.ver[i];
    		if(vis[y])
    			continue;
    		dfs(y);
    	}
    }
    
    int main()
    {
    	ios::sync_with_stdio(false);
    	int t;
    	cin >> t;
    	while(t--)
    	{
    		string s;
    		cin >> s;
    		memset(vis,0,sizeof(vis));
    		memset(in,0,sizeof(in));
    		rnt.clear();
    		g.renew();
    		djs.renew();
    		
    		set<pair<int,int>> st;
    		int flag = 0;
    		_for(i,0,s.size()-1)
    		{
    			if(st.count( {to(s[i]), to(s[i+1])} ) 
    			|| st.count( {to(s[i+1]), to(s[i])} ) )
    				continue;
    			if(djs.same( to(s[i]), to(s[i+1]) ) )
    			{
    				flag = 1;
    				break;
    			}
    			g.add(to(s[i]), to(s[i+1])),g.add(to(s[i+1]), to(s[i]));
    			st.insert({to(s[i]), to(s[i+1])});
    			djs.unite(to(s[i]), to(s[i+1]));
    			in[to(s[i])] ++,in[to(s[i+1])] ++;
    			if(in[to(s[i])] >= 3
    			|| in[to(s[i+1])] >= 3)
    			{
    				flag = 1;
    				break;
    			}
    		}
    		
    		if(flag)
    		{
    			printf("NO
    ");
    			continue;
    		}
    		
    		int sta;
    		_for(i,1,27)
    			if(in[i]==1)
    			 	sta = i;
    		if(s.size()!=1)
    			dfs(sta);
    		_for(i,1,27)
    			if(!vis[i])
    				 rnt += i+'a'-1;
    		printf("YES
    %s
    ",rnt.c_str());
    	}
    	return 0;
    }
    

    D. Fill The Bag

    既然盒子的大小就是二的倍数,那不妨把包的容量也拆成二进制。看看数据范围,盒子的大小最大也就那几十个,我们用一个数组 (cnt) 把他们装起来,$ cnt[5]=3$ 代表我们有 (3) 个 大小为 (2^5=32) 的盒子。

    然后我们观察一下,拆是要代价的,但是合起来不要代价。那么对于盒子每一位为 (1) 的情况,如果有对应的盒子大小最好,如果没有那咱们考虑两种情况来凑一个:合或者拆。先合后拆,因为说过了合不要代价。所谓合就是把小盒子攒起来攒成大盒子。我们考虑一下,从小到大遍历每一位的时候,我们遍历过的那些位的小盒子肯定是没用的,所以不妨把他们都合起来,合到我们当前遍历到的位上。如果合完发现还是合不出来,那我们就只能从最近的更高位上,如果有盒子就一路拆下来。可以证明这样一定最优。假如我们现在遍历到 (i=3) ,我们发现 (cnt[5]>0,cnt[6]>0) 则我们一定是把 (2^5=32) 的盒子拆了而不是把 (2^6=64) 的盒子通过多拆一步得到,否则可能不是最优,证明过程略。

    这样有拆有合,这个问题就算是完成了。时间复杂度 (O(max(mlogk,k^2))) ,其中 (k)(n) 在二进制表示下最大的位数,但其实 (k) 最大也就六十多啦,我们可以看成常数,这样的话时间复杂度就是 (O(mlogk))

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define _for(i,a,b) for(int i = (a);i < b;i ++)
    #define _rep(i,a,b) for(int i = (a);i > b;i --)
    #define INF 0x3f3f3f3f
    #define ZHUO 11100000007
    #define MOD 1000000007
    #define MIKUNUM 39
    #define pb push_back
    #define debug() printf("Miku Check OK!
    ")
    #define X first
    #define Y second
    #define maxn 139
    
    ll n, m;
    ll biao[maxn];
    ll cnt[maxn];
    ll rnt;
    void db()
    {
    	biao[0] = 1;
    	_for(i,1,80)
    		biao[i] = biao[i-1]*2;
    }
    void he(int x)
    {
    	cnt[x+1] += cnt[x]/2;
    }
    
    void chai(int x)
    {
    	int st = 0;
    	_for(i,x,80)
    		if(cnt[i])
    		{
    			st = i;break;
    		}
    	while(st!=x)
    	{
    		cnt[st] --;
    		cnt[st-1]+=2;
    		st --;
    		rnt ++;
    	}
    }
    int main()
    {
    	ios::sync_with_stdio(false);
    	int t;
    	cin >> t;
    	db();
    	while(t--)
    	{
    		cin >> n >> m;
    		ll sum = 0;
    		rnt = 0;
    		memset(cnt,0,sizeof(cnt));
    		_for(i,0,m)
    		{
    			ll tmp;
    			cin >> tmp;
    			sum += tmp;
    			cnt[lower_bound(biao,biao+64,tmp)-biao] ++;
    		}
    		if(sum < n)
    		{
    			printf("-1
    ");
    			continue;
    		}
    		bitset<maxn> target = n;
    		_for(i,0,80)
    		{
    			if(target[i])
    			{
    				if(cnt[i])
    				{
    					cnt[i]--;he(i);
    				}
    				else
    					chai(i);
    			}
    			else
    				he(i);
    		}
    		printf("%lld
    ",rnt);
    	}
    	return 0;
    }
    

    后面几题实力不大够,告辞

  • 相关阅读:
    lua判断字符串包含另一个字符串
    expect使用技巧
    Linux expect
    expect正则捕获返回结果
    修改alpine Linux的Docker容器的时区
    Dockerfile镜像优化,减小镜像
    Sed在匹配行前后加入一行
    scp的使用以及cp的对比
    rsync 的用法
    傅里叶系列(一)傅里叶级数的推导 (转)
  • 原文地址:https://www.cnblogs.com/Asurudo/p/12302930.html
Copyright © 2011-2022 走看看