• Codeforces Raif Round 1


    Link:
    Codeforces https://codeforces.com/contest/1428


    A. Box is Pull

    读错题目 × 1

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    int t;
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin >> t;
    		int aa, bb, cc, dd;
    	while(t--)
    	{
    		cin >> aa >> bb >> cc >> dd;
    		if(aa==cc)
    		{
    			cout<<abs(dd-bb)<<endl;continue;
    		}
    		if(bb==dd)
    		{
    			cout<<abs(aa-cc)<<endl;continue;
    		}
    		cout<<abs(dd-bb)+abs(cc-aa)+2<<endl;
    		continue;
    	}
    	return 0;
    }
    


    B. Belted Rooms

    没反应过来题意就直接打了,浪费半小时
    还 WA 了五发

    只要某一边是平的就可以过去遛一遛回来
    可以看成每个点有一个高度
    假如单调不递X,那随便哪个点都可以出去转一圈
    否则只要出去了就没法转一圈回来
    这时候,山顶的和谷底的要不没得出去要不没得回来
    山腰上的往低处走就会走到谷底被卡,往高处走不了

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    const int MAXN = 3e5 + 10;
    int t, n, ans;
    		char ch;
    		bool headee;
    		bool nota, notb;
    		char chzer;
    int main()
    {
    	cin >> t;
    	while(t--)
    	{
    		cin >> n;
    		headee = 0;
    		ans = 0;
    		nota = notb = false;
    		chzer = '0';
    		for (int i = 0; i<n; ++i)
    		{
    			cin>>ch;
    			if(!i)chzer=ch;
    			if(ch=='-')
    			{
    				if(!headee)++ans;
    				headee=1;
    				++ans;
    			}
    			else headee=0;
    			if (ch=='>') nota=true;
    			if(ch=='<')notb=true;
    		}
    		if (ch == chzer&&ch == '-') --ans;
    		if(!nota||!notb)cout<<n<<endl;
    		else cout<<ans<<endl;
    		
    	}
    	return 0;
    }
    


    C. ABBB

    怎么说呢,意外地很好写
    注意到 B 只要前面有字母都可以去掉,很好贪心
    完全不用缩点啊。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    int t, n, ans;
    char ch;
    string s;
    int main()
    {
    	cin >> t;
    	while(t--)
    	{
    		cin >> s;
    		n = s.length();
    		ans = 0;
    		for(int Ben=0, Aen=0, i=0; i<n; ++i)
    		{
    			ch = s[i];
    			if(ch=='A')
    			{
    				++Aen;
    			}
    			if(ch=='B')
    			{
    				if(Aen)
    				{
    					--Aen;
    					++ans;
    				}
    				else
    				{
    					if(Ben && !Aen)
    					{
    						--Ben;
    						++ans;
    					}
    					else ++Ben;
    				}
    			}
    		}
    		cout<<n-(ans<<1)<<endl;
    	}
    	return 0;
    }
    


    D. Bouncing Boomerangs

    睡了
    反弹不会超过三次,所以很容易根据从哪里进哪里出约束一波
    比如说从某一行出去,那么那一行必定有一段是不能被堵住的。

    对不起我审题审错了
    Every row and every column in your configuration should have at most two targets each.

    对不起我又审错了
    原来可以直接从上面飞走或者从右边飞走
    而且根本没说要从哪里出去


    反弹次数为0的,那一列啥都不要放就可以了
    反弹次数为2的,可以且只可以填一行,然后这一行直接废了
    然后填的这两个,右边那一列那个列肯定也会有个什么要射上来,这个射上来的必须往右
    同时右边那一列那个处境尴尬,别的啥也不能干。那列等于废了。
    左边那一列那个倒是还有一个用处,就是给反弹次数为3的最后一击

    反弹次数为1的,填的那个位置要么接3的要么作为2的第二个要么直接废了那一行一列


    反弹次数为3的,首先有一行一列废了,左上角那个可以且只能用来反弹3最后一下
    右边那一列呢,下面射上来的必须要么弹2次要么1次,也回到上面的情况
    画个图,模拟。 很容易发现只有3可以跟别的有最多的关联,可以连成一个阶梯状
    那么到底是优先跟1/2贴贴好还是优先跟3贴贴好呢?

    你看,2简直是1的绝配,所以左边2右边1优先它俩凑一对
    剩下的凑合凑合,反正省的空间都一样。顶多是省左上角那一个点。
    为啥这么说呢,因为某一列向上射如果要反弹三次,那么左上角那点的那一行废了,那一列只能上接
    反弹一次,那么那一行因为前面2配完了也废了,那一列也只能上接,所以其实是等价的。


    我的表演到此结束,谢谢大家,接下来请大家尽情地大模拟
    注意哦,假如有2没法跟1配对,那这个2就没地方出去了,所以无解
    再注意一下,2跟1配对由于可能会用来接上面的3(作为结尾),所以我建议放在最底下。


    很有趣的事实:这道题讲起来并不用这么麻烦,具体参考洛谷题解第一条
    EDIT 更加有趣的是,样例起了很大的提示作用。


    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    const int MAXN = 1e5 + 10;
    #define PII pair<int, int>
    int n, a[MAXN], tot = 0;
    int Miserable = 0, Deleted = 1;
    int FreeLines;
    int Pos[MAXN];
    bool LastAvailable[MAXN];
    PII Ans[MAXN<<1];
    bool Removed[MAXN];
    bool LackingLast = false;
    int LastColumnHigh = 1;
    int FreeLinesDown; 
    int main()
    {
    	scanf("%d", &n);
    	FreeLines = 1;
    	FreeLinesDown = n;
    	for (int i = 1; i <= n; ++i)
    	{
    		cin >> a[i];
    		if (a[i]==2) 
    		{
    			Pos[++Miserable]=i;
    			continue;
    		}
    		if (a[i]==1)
    		{
    			if (Miserable < Deleted)
    			{
    				LastAvailable[i] = true;
    				continue;
    			}
    			LastAvailable[Pos[Deleted]] = true;
    			Removed[Pos[Deleted]] = true;
    			Removed[i] = true;
    			Ans[++tot] = make_pair(FreeLinesDown, Pos[Deleted]);
    			Ans[++tot] = make_pair(FreeLinesDown, i);
    			--FreeLinesDown;
    			++Deleted;
    			continue;
    		}
    		if (!a[i]) Removed[i] = true;
    	}
    	
    	if (Miserable >= Deleted)
    	{
    		puts("-1");
    		return 0;
    	}
    	
    	for (int i = 1; i <= n; ++i)
    	{
    		if (LastAvailable[i])
    		{
    			if (LackingLast)
    			{
    				Ans[++tot] = make_pair(LastColumnHigh, i);
    				if (a[i] != 2) //*
    					Ans[++tot] = make_pair(FreeLines, i);
    				++FreeLines;
    				LackingLast = false;
    				continue;
    			}
    			if (Removed[i]) continue;
    			Ans[++tot] = make_pair(FreeLines, i);
    			++FreeLines;
    			continue;
    		}
    		if (Removed[i])	continue;
    		
    		// a[i] == 3
    		if (LackingLast)
    		{
    			Ans[++tot] = make_pair(LastColumnHigh, i);
    			LastColumnHigh = FreeLines;
    			Ans[++tot] = make_pair(FreeLines, i);
    			++FreeLines;
    			continue;
    		}
    		Ans[++tot] = make_pair(FreeLines, i);
    		LastColumnHigh = FreeLines;
    		++FreeLines;
    		LackingLast = true;
    		//continue;
    	}
    	
    	if (FreeLines > FreeLinesDown + 1)
    	{
    		puts("-1");
    		return 0;
    	}
    	
    	if (LackingLast)
    	{
    		puts("-1");
    		return 0;
    	}
    	
    	printf("%d
    ", tot);
    	for (int i = 1; i <= tot; ++i)
    	{
    		printf("%d %d
    ", Ans[i].first, Ans[i].second);
    	}
    	
    	return 0;
    }
    


    E. Carrots for Rabbits

    开了然后不会做

    好吧
    假如只有一根萝卜,很容易想到直接平均分就好了,这个用不等式证明即可

    假如有两根萝卜呢?
    很容易想到,实际上对两根胡萝卜也可以按照只有一根萝卜的模式,两根分别平均分就好了
    问题就在次数要怎么分配


    比较显然的想法是按照长度比例分配
    但是这个显然错误
    另外直觉来说,利益(或者说这么安排能够达到的最优结果)=f(分配的切割数) 可能是一个 ↗ 极大值 ↘ 的函数
    假如的确是的话可以考虑找一找那个极大值点,不过有些难检验


    再考虑一个经典的想法,假如有的萝卜短,就有的萝卜(比萝卜的平均长度)长
    那么首先可以按 (k) 算出平均每个萝卜可以切几刀。
    比总长除以 (k) 的商还要小的萝卜就别切了,然后剩下的完全不知道怎么做
    不过剩下的肯定还是要切的

    如果稍微多思考一下就可以发现这里有一个单调性
    就是
    越长的萝卜必被切得越碎
    而且随着切的段数越来越多,贡献的增量也越来越小
    而这个贡献的增量显然是可以求的
    那不妨直接每次操作都找一找切谁好一点
    这个找的操作可以在 (O(log n)) 时间内完成。


    对没错,所以最后不是枚举每一段,而是枚举每一切。
    所以根本不是考虑每一段切几块,这东西是顺带的。
    如果思路被卡在这个方向上就那啥了。

    结果最后发现不是DP
    还是挺有意思的(虽然大概是我菜

    EDIT 其实非常显然应该这么搞。比较nowcoder)
    另外官方题解给了一个强化版,我就单独贴了
    https://www.cnblogs.com/ccryolitecc/p/13848301.html


    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
    using namespace std;
    const int MAXN = 1e5 + 10;
    #define PII pair<long long int, int>
    int n, k;
    long long a[MAXN];
    long long Eat_Time[MAXN];
    long long After_Cut;
    long long PreLength;
    long long Cut_Rest;
    int Cut_Times[MAXN];
    struct cmp
    {
    	bool operator () (const PII& a, const PII& b)
    	{
    		return Eat_Time[a.second]-a.first < Eat_Time[b.second]-b.first;
    	}
    };
    priority_queue<PII, vector<PII>, cmp> Q;
    long long Ans = 0;
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin >> n >> k;
    	for (int i = 1; i <= n; ++i)
    	{
    		cin >> a[i];
    		Cut_Times[i] = 1;
    		Eat_Time[i] = a[i] * a[i];
    		PreLength = a[i] >> 1;
    		After_Cut = (PreLength * PreLength)<<1;
    		if (a[i] & 1)
    		{
    			After_Cut -= PreLength * PreLength;
    			After_Cut += ((a[i] >> 1) + 1) * ((a[i] >> 1) + 1);
    		}
    		Q.push(make_pair(After_Cut, i));
    	}
    	int qf;
    	k -= n;
    	while (k--)
    	{
    		qf = Q.top().second;
    		Eat_Time[qf] = Q.top().first;
    		Q.pop();
    		if (Cut_Times[qf] == a[qf]) continue;
    		
    		Cut_Times[qf] += 2;
    		PreLength = a[qf] / Cut_Times[qf];
    		Cut_Rest = a[qf] - PreLength * Cut_Times[qf];
    		
    		After_Cut = PreLength * PreLength * Cut_Times[qf];
    		After_Cut -= PreLength * PreLength * Cut_Rest;
    		After_Cut += (PreLength + 1) * (PreLength + 1) * Cut_Rest;
    //		cout << qf << " " << PreLength << " " << Cut_Times[qf] << " " << Cut_Rest << " " << After_Cut << "FAQ
    ";
    		
    		--Cut_Times[qf];
    		
    		Q.push(make_pair(After_Cut, qf));
    	}
    	for (int i = 1; i <= n; ++i)
    	{
    		Ans += Eat_Time[i];
    	}
    	cout << Ans;
    	return 0;
    }
    
  • 相关阅读:
    基本数据类型(二)
    jquery 基础
    CSS 基础
    Hyperledger Fabric Ordering Service过程
    Hyperledger Fabric Transaction Proposal过程
    Hyperledger Chaincode启动过程
    Hyperledger Fabric1.0 整体结构
    golang学习
    数字签名详解
    设置MongoDB课程环境
  • 原文地址:https://www.cnblogs.com/ccryolitecc/p/13834502.html
Copyright © 2020-2023  润新知