(因为我是若只所以只会写这几题题解)

A   chmod

点此跳转

打表模拟即可

参考代码
#include<bits/stdc++.h>
using namespace std;

string a[8] = {"---","--x","-w-","-wx","r--","r-x","rw-","rwx"};

void solve(){
	string s;
	cin >> s;
	int n = 3;
	while(n--){
		cout << a[s[2 - n] - '0'];
	}
	cout << endl;
	return ;
}

int main(){
	int t;
	cin >> t;
	while(t--){
		solve();
	}
	return 0;
}

B   Expression Matrix

打表求解即可

提供一种不需要打表的做法

大体思路为先填上乘号再把符合条件的乘号改为加号即可

参考代码
#include<bits/stdc++.h>
#define int long long
using namespace std;

int res_s(string s){
	stack<int> stk;
	int current_num = 0;
	char current_op = '+';
	s += '+';
	for(int i = 0; i < s.length(); i++){
		if(s[i] == '1') current_num = current_num * 10 + s[i] - '0';
		else{
			if(current_op == '+') stk.push(current_num);
			else if(current_op == '*'){
				current_num = current_num * stk.top();
				stk.pop();
				stk.push(current_num);
			}
			current_num = 0; current_op = s[i];
		}
	}
	while(stk.size()){
		current_num += stk.top();
		stk.pop();
	}
	return current_num;
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	int n, m;
	cin >> n >> m;
	char mp[11][11];
	for(int i = 0; i < n; i++){
		for(int j = 0; j < m; j++){
			mp[i][j] = '1';
			if ((i + j) % 2 == 0 && i != 0 && i != n - 1 && j != 0 && j != m - 1){
				 mp[i][j] = '*';
			}
		}
	}
		
    for(int i = 0; i < n; i++){
    	for(int j = 0; j < m; j++){
    		if(mp[i][j] != '*') continue;
    		string s1, s2, s3, s4;
    		for(int k = 0; k < i; k++){
    			s3 += mp[k][j];
			}
			for(int k = 0; k < j; k++){
				s1 += mp[i][k];
			}
			for(int k = j + 1; k < m; k++){
				s2 += mp[i][k];
			}
			for(int k = i + 1; k < n; k++){
				s4 += mp[k][j];
			}
			//cout << "i=" << i + 1 <<" j=" << j + 1<< " s1=" << s1 << " s2=" << s2 << " s3=" << s3 << " s4=" << s4 << endl;
			if(res_s(s1) == 11 && res_s(s2) == 11 && res_s(s3) == 11 && res_s(s4) == 11){
				mp[i][j] = '+';
			}
		}
	}
	for(int i = 0; i < n; i++){
    	for(int j = 0; j < m; j++){
    		if(mp[i][j] != '*') continue;
    		string s1, s2, s3, s4;
    		for(int k = 0; k < j; k++){
    			s1 += mp[i][k];
			}
			for(int k = j + 1; k < m; k++){
				s2 += mp[i][k];
			}
			if(res_s(s1) == 11 && res_s(s2) == 11){
				mp[i][j] = '+';
			}
		}
	}
	for(int i = 0; i < n; i++){
    	for(int j = 0; j < m; j++){
    		if(mp[i][j] != '*') continue;
    		string s1, s2, s3, s4;
    		for(int k = 0; k < i; k++){
    			s3 += mp[k][j];
			}
			for(int k = i + 1; k < n; k++){
				s4 += mp[k][j];
			}
			if(res_s(s3) == 11 && res_s(s4) == 11){
				mp[i][j] = '+';
			}
		}
	}
	for(int i = 0; i < n; i++){
		for(int j = 0; j < m; j++){
			cout << mp[i][j];
		}
		cout << endl;
	}
	return 0;
}

C   Seats

由i到ai建边会得到内向基环树森林(包括环)和单链有向树

对于有向树,其树链的深度就是最大值

所以我们建反边,可以发现一条链上最多一个点的序号大于n

从每个编号大于n的来查找最长链计入答案即可。

对于内向基环树,拓扑排序标记环上的点加入答案即可

参考代码
#include<bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10;
int seat[N];
int h1[N],e1[N],ne1[N],idx1;//用于建反边
int h[N],e[N],ne[N],idx;

int in[N];
bool st[N];
int n;

void add(int a, int b){
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx++;
}

void add1(int a, int b){
	e1[idx1] = b;
	ne1[idx1] = h1[a];
	h1[a] = idx1++;
}

void dfs(int u, int d, int &res){
	if(u <= n){
		st[u] = 1;
		res = max(res, d);
	}
	for(int i = h1[u]; i != -1; i = ne1[i]){
		dfs(e1[i], d + 1, res);
	}
}

int main(){
	int ans = 0;
	memset(h, -1, sizeof h);
	memset(h1, -1, sizeof h1);
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> seat[i];
		in[seat[i]]++;
		add1(seat[i],i);
		add(i,seat[i]);
	}
  //遍历n+1序号后的座位,找最长链
	for(int i = n + 1; i <= 2 * n; i++){
		int res = 0;
		dfs(i, 0, res);
		ans += res;
	}
  
	queue<int> q;
	for(int i = 1; i <= n; i++){
		if(!st[i] && !in[i]){
			st[i] = 1;
			q.push(i);
			//cout << "i=" << i << endl;
		}
	}
  //让不在环上的点出队
  
	while(!q.empty()){
		int t = q.front();
		//cout << "t=" << t << endl;
		q.pop();
		for(int i = h[t]; i != -1; i = ne[i]){
			//cout << "in[" << e[i] << "]-- "<< endl;
			in[e[i]]--;
			if(in[e[i]] == 0){
				st[e[i]] = 1;
				q.push(e[i]);
			}
		}
	}
  //统计没有出队的点,这些点一定在环上
	for(int i = 1; i <= n; i++){
		if(!st[i]) {
			//cout << "i=" << i << endl;/
			ans++;
		}
	}
	cout << ans << endl;
	return 0;
}

F   Try a try, AC is OK

点此跳转

注意到a&b不会大于a或b的其中一个,所以最大值即为最优解

找出最大值并输出即可

参考代码
#include<bits/stdc++.h>
using namespace std;

void solve(){
	int n, a;
	cin >> n;
	int max_socre = INT_MIN;
	while(n--){
		cin >> a;
		if(a > max_socre) max_socre = a;
	}
	cout << max_socre << endl;
	return ;
}

int main(){
	int t;
	cin >> t;
	while(t--){
		solve();
	}
	return 0;
}

G   Disappearing Number

点此跳转

我的想法是对于k位数n,先求出小于k位数的不含x的自然数的数量,再找出等于k位数的数中不含x且小于n的数的数量

当求小于k位数的数的数量的时候,

首位有除去x的八个数可以选(0-9十个数去掉x和0),

其他位都有九个数可以选(0-9去掉x),

所以不包括0有

个数字

求位数相等时有多少个不含x的数小于n的时候,

我们从最大位往最小位依次看看有多少数可以选

设第i位上的数为

如果第一位比x大

第一位可以选择0至去掉0和x 中任意一个数

那么当第一位选择 0至去掉0和x 中任意一个数时(共-2个)

此时后面的每一位都可以选 0至9中去掉x的数(每一位有9个可以选)

如果第一位比x小

第一位可以选择0至去掉0 中任意一个数

那么当第一位选择 0至去掉0 中任意一个数时(共-1个)

此时后面的每一位都可以选 0至9中去掉x的数(每一位有9个可以选)

然后以此类推(注意到不是第一位的时候0时可以选的)

得出当位数相等时,可以这样求小于n的数的个数

//求等于位数有多少个数,即res; 
	int res = 0;
	for(int i = bit - 1; i >= 0; i--){
		//取出每一位数 
		int m = n / (poww(10, i));
		m %= 10;
		//计算时判断是否是第一位,是否大于x
		if(i != bit - 1){
			res += ((m < x) ? (poww(9, i) * (m)) : (poww(9, i) * (m - 1)));
		}
		else{
			res += ((m < x) ? (poww(9, i) * (m - 1)) : (poww(9, i) * (m - 2)));
		}
	}

然后将小于n的位数的数和等于n位数的数相加再加上本身输出即可

完整代码1
#include<bits/stdc++.h>
#define int long long
using namespace std;


//因为自带的pow是浮点数计算,有精度误差,所以重写一下 
//ps:因为这玩意害得我wa四次
int poww(int n,int x){
	int ans = 1;
	for(int i = 1; i <= x; i++){
		ans *= n;
	}
	return ans;
}

//求数的位数 
int bitt(int n){
	int bit = 0;
	while(n){
		n /= 10;
		bit++;
	}
	return bit;
}

void solve(){
	int n, x;
	cin >> n >> x;//数字x消失了 
	
	//如果小于10的话直接输出答案 
	if(n < 10){
		if(n > x) cout << n << endl;
		else cout << n + 1 << endl;
		return ;
	}
	//如果等于0的话直接输出答案 
	if(n == 0){
		cout << '0';
		return ;
	}
	//求小于位数有多少个数,即ans; 
	int bit = bitt(n);
	int ans = poww(9,bit - 1);
	//求等于位数有多少个数,即res; 
	int res = 0;
	for(int i = bit - 1; i >= 0; i--){
		//取出每一位数 
		int m = n / (poww(10, i));
		//cout << "m1=" << m << endl;
		m %= 10;
		//cout << "m=" << m << endl;
		//计算时判断是否是第一位 ,是否大于x 
		if(i != bit - 1){
			res += ((m < x) ? (poww(9, i) * (m)) : (poww(9, i) * (m - 1)));
		}
		else{
			res += ((m < x) ? (poww(9, i) * (m - 1)) : (poww(9, i) * (m - 2)));
		}
	}
	//cout << "ans="<< ans << "  res=" << res <<endl; 
	//加一是把本身加上 
	cout << ans + res + 1 << endl;
	return ;
}

signed main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	int t;
	cin >> t;
	while(t--){
		solve();
	}
	return 0;
}


但是这个题并不需要这么麻烦

我们只需要利用进制转换的思想把这个数映射为对应九进制再转化为十进制即可

参考代码2
#include<bits/stdc++.h>
#define int long long
using namespace std;

//将九进制转化为十进制 
int nine_to_ten(string s){
	int res = 0;
	for(int i = 0; i < s.length(); i++){
		res = res * 9 + (s[i] - '0');
	}
	return res;
}

void solve(){
	string n;
	cin >> n;
	int x;
	cin >> x;
	string n_9;//转换后九进制数 
	for(int i = 0; i < n.length(); i++){
		if(n[i] - '0' < x){
			n_9 += n[i];
		}
		else{
			n_9 += n[i] - 1;
		}
	}
	cout << nine_to_ten(n_9) + 1 << endl;
}

signed main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	int t;
	cin >> t;
	while(t--){
		solve();
	}
	return 0;
}


L   chess

点此跳转

注意到当先手拿到的 末位为 0 时,

无论怎么拿都会拿成末位非 0。

所以策略很显然,

后手只需要拿走个位上的数字个棋 子就可以保证先手拿到的 末位为 0。

必败态(x = 0)必然存在于 x 末位为 0 的集合内。

所以末尾一位为 0 的时候先手必败,反之则必胜。

那么令 的末位不为 0,

k 只需要取最小的非因子即可,

最小非因子是对数级别的,可以通过暴力枚举获得

(因为不知道怎么讲所以直接复制了官方题解,理解一下这个题很容易)

参考代码
#include<bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;

void solve(){
	int n;
	cin >> n;
	for(int i = 1; i <= n; i ++){
		if(n % i != 0){
			cout << i <<endl;
			return ;	
		}
	}
}

signed main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	int t;
	cin >> t;
	while(t--){
		solve();
	}
	return 0;
}


M   Window Decoration

点此跳转

注意到大正方形可以分成四个小正方形,用小正方形的中心坐标代表这个正方形

把坐标扩大俩倍这样四个小正方形中心的坐标就都是整数了

参考代码
#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e4 + 9;
pair<int,int> p[N];
int n;
bool mp[201][201];

signed main(){
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> p[i].first >> p[i].second;
		mp[p[i].first * 2 - 1][p[i].second * 2] = 1;
		mp[p[i].first * 2 + 1][p[i].second * 2] = 1;
		mp[p[i].first * 2][p[i].second * 2 + 1] = 1;
		mp[p[i].first * 2][p[i].second * 2 - 1] = 1;
	}
	double ans = 0.0;
	for(int i = 1; i <= 200; i++){
		for(int j = 1; j <=200; j++){
			if(mp[i][j]) ans += 0.5;
		}
	}
	cout << ans;
	return 0;
}