dengch

 

Atcoder354题解

A.Exponential Plant

求解满足 2n - 1 > h时,n的值

#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <set>

using namespace std;

typedef long long LL;
typedef pair<int,int>PII;

int h;

int main(){
	cin >> h;
	h ++;

	int res = 0;
	while(h){
		res ++;
		h /= 2;
	}

	cout << res << endl;

	return 0;
}

B.AtCoder Janken 2

排个序即可(sort默认按照字典序排序)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <set>

using namespace std;

typedef long long LL;
typedef pair<string,int>PSI;
const int N = 110;

vector<PSI>users;
int n;

int main(){
	cin >> n;

	int t = 0;
	for(int i = 0; i < n; i ++){
		string username;
		int rating;
		cin >> username >> rating;
		t += rating;
		users.push_back({username,rating});
	}

	sort(users.begin(),users.end());

	cout << users[t % n].first << endl;

	return 0;
}

C. AtCoder Magics

按A从小到大排序,然后从右向左枚举,并维护一个最小cost,若当前的card的c值大于cost,则需要discard(存在A比当前card的A更大,且cost比它小的card)。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <set>
#include <queue>

using namespace std;

typedef long long LL;
const int N = 200010;
typedef pair<pair<int,int>,int>PPI;
vector<PPI>cards;
int n;
bool discard[N];

int main(){
	cin >> n;

	for(int i = 1; i <= n; i ++){
		int a,c;
		cin >> a >> c;

		cards.push_back({{a,c},i});
	}

	sort(cards.begin(),cards.end());
	int cost = 1e10;
	int discardCnt = 0;
	for(int i = cards.size() - 1; i >= 0; i --){
		if(cards[i].first.second > cost){
			discard[cards[i].second] = true;
			discardCnt ++;
		}
		cost = min(cost,cards[i].first.second);
	}

	cout << n - discardCnt << endl;
	for(int i = 1; i <= n; i ++){
		if(!discard[i])cout << i << " ";
	}

	cout << endl;

	return 0;
}

D.AtCoder Wallpaper

可以发现该图像存在一个基本图形——一个2*4的矩形,由该基本图形不断重复构成整个图像。可以参考二维前缀和的思路,将求解给定矩形中阴影部分的面积转化为求解以原点作为左下角的四个矩形的代数和,即

\(S = S_{ABCD} - S_{ADEF} - S_{ABHG} + S_{AFOG}\)
至于每个每个矩形中阴影部分的面积如何求,也可以将其分为4部分:第一部分是其含有的基本图形的数量,第二部分是多余的竖直部分,第三部分是多余的横向部分S3,这两部分也有各自的基本图形,因此只需计算包含多少个基本图形即可,最后一部分暴力枚举即可。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <set>
#include <queue>

using namespace std;

typedef long long LL;
typedef pair<int,int>PII;
int a,b,c,d;
const int OFFSET = 1e9;

int basicS[2][4] = {{2,1,0,1},
{1,2,1,0}};

LL getSquare(LL x,LL y){
	LL s = 0;
	//该矩形包含的2*4基本图形的数量,S1
	s += x / 4 * (y / 2) * 8;
	//S2
	for(int i = 0; i < x % 4; i ++){
		int sum = 0;
		for(int j = 0; j < 2; j ++){
			sum += basicS[j][i];
		}
		s += sum * (y / 2);
	}

	//S3
	for(int i = 0; i < y % 2; i ++){
		int sum = 0;
		for(int j = 0; j < 4; j ++){
			sum += basicS[i][j];
		}
		s += sum * (x / 4);
	}

	//S4
	for(int i = 0; i < x % 4; i ++){
		for(int j = 0; j < y % 2; j ++){
			s += basicS[j][i];
		}
	}

	return s;
}

int main(){
	cin >> a >> b >> c >> d;
	//让坐标都变为正数,保证其在第一象限
	a += OFFSET;
	b += OFFSET;
	c += OFFSET;
	d += OFFSET;

	LL res = getSquare(c,d) - getSquare(a,d) - getSquare(c,b) + getSquare(a,b);
	cout << res << endl;

	return 0;
}

E. Remove Pairs

博弈论题目,将刚开始n张卡牌都在桌子上看作初始局面,此后每次操作(如果能的话),都会去除两张卡牌,即转换为另一个局面。在两人都采取最优抽卡方式的前提下,如果存在某种抽卡方式使得剩下的局面是必败局面,则先手必胜,否则先手必败。普通搜索会TLE,需要使用记忆化搜索,即将已经遍历过的局面存储起来,避免多次遍历从而减少时间开销。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <queue>

using namespace std;

typedef long long LL;
typedef pair<LL,LL>PLL;
const int N = 20,M = 1 << 20;

int n,mask;
int front[N],back[N];
int visit[M];
bool mem[M];

bool dfs(int m){
	if(visit[m])return mem[m];
	else visit[m] = true;
	if(m == 0){
		mem[m] = false;
		return false;
	}
	for(int i = 0; i < n; i ++){
		for(int j = i + 1; j < n; j ++)
		if(m >> i & 1 && m >> j & 1 && (front[i] == front[j] || back[i] == back[j])){
			int newMask = m ^ (1 << i) ^ (1 << j);
			bool canWin = dfs(newMask);
			if(!canWin){
				//抽走卡牌后剩下的是必败局面,则先手获胜
				mem[m] = true;
				return true;
			}
		}
	}
	//无论如何抽卡牌,剩下的局面都不会是必败局面,因此先手必败
	mem[m] = false;
	return false;
}

int main(){
	cin >> n;
	//将n张卡牌压缩为n位,第i位为1表示第i张卡还在桌子上
	//起初所有卡牌都在桌子上,这也是初始局面,此后,每执行一次操作,就会造成一个新局面
	mask = (1 << n) - 1;

	for(int i = 0; i < n; i ++){
		cin >> front[i] >> back[i];
	}

	bool res = dfs(mask);
	if(res)puts("Takahashi");
	else puts("Aoki");

	return 0;
}

posted on 2024-06-01 11:36  BkDench  阅读(18)  评论(0)    收藏  举报

导航