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;
    }
    

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

  • 相关阅读:
    Python 爬虫js加密破解(一) 爬取今日头条as cp 算法 解密
    Python 爬虫实例(2)—— 爬取今日头条
    Python 爬虫实例(1)—— 爬取百度图片
    python 操作redis之——HyperLogLog (八)
    python 操作redis之——有序集合(sorted set) (七)
    Python操作redis系列之 列表(list) (五)
    Python操作redis系列以 哈希(Hash)命令详解(四)
    Python操作redis字符串(String)详解 (三)
    How to Install MySQL on CentOS 7
    Linux SSH远程文件/目录 传输
  • 原文地址:https://www.cnblogs.com/Asurudo/p/12302930.html
Copyright © 2011-2022 走看看