专栏文章

2025寒假专场9

题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqecdrt
此快照首次捕获于
2025/12/04 03:25
3 个月前
此快照最后确认于
2025/12/04 03:25
3 个月前
查看原文
数据范围较小, 直接模拟
CPP
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int n, m;
int p[N];
set<int>S[N];

int main(){
	scanf("%d%d", &n, &m);
	for(int i = 0; i < n; i++){
		int cnt;
		scanf("%d%d", &p[i], &cnt);
		while(cnt--){
			int x; scanf("%d", &x);
			S[i].insert(x);
		}
	}
	
	for(int i = 0; i < n; i++){
		for(int j = 0; j < n; j++){
			if(i != j && p[i] >= p[j]){
				bool ok = true;
				for(auto x: S[i]){
					if(S[j].count(x) == 0){
						ok = false;
						break;
					}
				}
				if(ok && (p[i] > p[j] || S[j].size() > S[i].size())){
					puts("Yes");
					return 0;
				}
			}
		}
	}
	puts("No");
	return 0;
}
对于一个字符串和其翻转后的字符串,用字典序更小的来表示这个字符串, 可以利用set来去重。注意,将每个字符串字典序小的放入set中。
CPP
#include <bits/stdc++.h>
using namespace std;
set<string>se;
int n;
void solve(){
    cin >> n;
    for (int i = 1; i <= n; i++ ){
        string s;
        cin >> s;
        string t = s;
        reverse(t.begin(), t.end());
        if (s > t) swap(s, t); // 只把字典序小的放进集合 
        se.insert(s);
    }

    cout << se.size() << "\n";
}

int main(){
	solve();
    return 0;
}
数据范围较小,暴力枚举nn个人分到的组别,再判断是否冲突。
CPP
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
int a[N], b[N];
int n, t, m;
int vis[N], ans; // vis[i]记录第i个运动员的组别 
void dfs(int h, int tot){
	if(h == n + 1){
		if(tot != t) return ;
		for(int i = 1; i <= m; i++){
			if(vis[a[i]] == vis[b[i]])
				return ;
		}
		ans++;
		return;
	}
	for(int i = 1; i <= tot + 1; i++){
		vis[h] = i;
		dfs(h + 1, max(i, tot)); // 下一个人的组数是较大值 
		vis[h] = 0;
	}
}
int main(){
	scanf("%d%d%d", &n, &t, &m);
	for(int i = 1; i <= m; i++)
		scanf("%d%d", &a[i], &b[i]);
	dfs(1, 0);
	printf("%d\n", ans);
	return 0;
}
直接计算显然是O(n2)O(n^2)的时间复杂度。
这里我们枚举以ii位置为右端点时的贡献。
  • s[i]s[i]0, 因为0与任何数运算的结果都是1,所以前面00 ~i1i-1(索引从00开始)都会贡献答案。
  • s[i]s[i]1, 找到左侧最近的0的位置为pp。则pp前面开始的所有起点到pp时,结果肯定为11, 那么先观察一下ii结尾的连续的11的长度lenlen,这里lenlen个1贡献为(len+1)/2(len + 1) / 2。 另外,若lenlen为奇数,则以pp为结尾的部分运算结果为11,再与这lenlen11运算的话,不会贡献答案,只有pp位置上的00可以贡献答案。 若lenlen为偶数,则恰好相反,00~p1p-1都能贡献答案,而pp不能贡献。
CPP
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
long long ans = 0;

int main(){
	cin >> n >> s;
	int p = -1;
	for(int i = 0; i < n; i++){
		if(s[i] == '0'){
			p = max(p, i); // 最后一个0的位置
			ans += 1ll * i; // 0~i-1都有贡献 
		}
		else{
			int len = i - p; // i之前连续的1的长度
			ans += 1ll * (len + 1) / 2; //连续1的贡献
			if(p != -1){ // 左侧最近的0存在 
				if(len % 2 == 1) ans++; // 只有p位置(为0)会贡献 
				else ans += 1ll * p; // 否则0~p-1都会产生贡献 
			}	
		}
	}
	cout << ans << '\n'; 
	return 0;
}
先沿着一个方向走到底,走到下一步是墙才会停下来,然后再以目前点继续沿着一个方向走到底...所以有可能会走到重复的点。
将走过的点标记一下,最后统计标记过的点有多少即可。
CPP
#include<bits/stdc++.h>
using namespace std;
const int N = 210;
int vis[N][N];
int n, m;
string st[N];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
bool ok(int x, int y){
	return  x >= 0 && x < n && y >= 0 && y < m;
}
void dfs(int x, int y){
	for(int i = 0; i < 4; i++){
		int tx = x, ty = y;
		while(1){
			if(!ok(tx + dx[i], ty + dy[i]) || st[tx + dx[i]][ty + dy[i]] == '#'){
				if(!vis[tx][ty]){
					vis[tx][ty] = 1;
					dfs(tx, ty);	
				}
				break;
			}
			vis[tx][ty] = 1;
			tx += dx[i];
			ty += dy[i]; 	
		}
	}
}
int main(){
	scanf("%d%d", &n, &m);
	for(int i = 0; i < n; i++)
		cin >> st[i];
	vis[1][1] = 1;
	dfs(1, 1);
	int ans = 0;
	for(int i = 0; i < n; i++)
		for(int j = 0; j < m; j++)
			ans += vis[i][j];
	printf("%d\n", ans);	
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...