CSP-J模拟赛day5——解析+答案

题解

T1 三点连通块

考虑每个点作为中心时,方案数量实际上就是从相邻点中任意选两个组成三点连通块。

因此统计每个点的度,记为 d [ i ] d[i] d[i],对每个点来说方案数是 d [ i ] ∗ ( d [ i ] − 1 ) / 2 d[i] * (d[i] - 1) / 2 d[i]∗(d[i]−1)/2。

加和即可。注意long long。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

long long son[100010],k;
long long q[100010];
int main(){
	int n;
	cin>>n;
	for (int i=1;i<n;i++){
		int a,b;
		cin>>a>>b;
		son[a]++;
		son[b]++;
	}
	for (int i=2;i<=n;i++){
		q[i]=q[i-1]+i-1;
	}
	for (int i=1;i<=n;i++){
		k+=q[son[i]];
	}
	cout<<k;
	return 0;
}

T2 矩阵魔法

普通的模拟。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int n,m;
int a[1505][1505];
int b[1505][1505];
int cnt=0;
void right(int x,int y,int r){
	int sx=x-r,sy=y-r;
	int ex=x+r,ey=y+r;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			b[i][j]=a[i][j];
		}
	}
	for(int i=sx;i<=ex;i++){
		for(int j=sy;j<=ey;j++){
			b[x-y+j][x+y-i]=a[i][j];
			//b[x+y-j][y-x+i]
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			a[i][j]=b[i][j];
		}
	}
}
void left(int x,int y,int r){
	int sx=x-r,sy=y-r;
	int ex=x+r,ey=y+r;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			b[i][j]=a[i][j];
		}
	}
	for(int i=sx;i<=ex;i++){
		for(int j=sy;j<=ey;j++){
			b[x+y-j][y-x+i]=a[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			a[i][j]=b[i][j];
		}
	}
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cnt++;
			a[i][j]=cnt;
		}
	}
	for(int i=1;i<=m;i++){
		int x,y,r,z;
		scanf("%d%d%d%d",&x,&y,&r,&z);
		if(z==0){
			right(x,y,r); 
		}else{
			left(x,y,r); 
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			printf("%d ",a[i][j]);
		}
		printf("\n");
	}

	return 0;
}

T3 汪汪队立大功

先不考虑后面可能有机关跳过的问题,考虑每个机会使用后带来的影响:

首先不需要消耗这个机关的能量值,但是后续的所有机关都需要加一,所以减少的能量消耗为 a [ i ] − ( n − i ) a[i] - (n - i) a[i]−(n−i)

然后你会发现选 k k k个机关的话,这 k k k个机关自己多消耗的加一是不存在的(因为被跳过了)

所以刚才算的答案比实际的消耗多了 k \* (k - 1) / 2的能量,减掉即为答案。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

long long n,k,a[1010],dp[1010][1010];

int main(){
//	freopen("dog.in","r",stdin);
//	freopen("dog.out","w",stdout);
	int t;
	cin>>t;
	while (t--){
		cin>>n>>k;
		for (int i=1;i<=n;i++){
			cin>>a[i];
		}
		for (int i=0;i<=n;i++){
			for (int j=0;j<=k;j++){
				dp[i][j]=INT_MAX;
			}
		} 
		for (int i=0;i<=k;i++){
			dp[0][i]=0; 
		} 
		for (int i=1;i<=n;i++){
			for (int j=0;j<=k;j++){
				if(j==0)dp[i][j]=dp[i-1][j]+a[i]; 
				else dp[i][j]=min(dp[i-1][j-1],dp[i-1][j]+a[i]+j);
			}
		}
		cout<<dp[n][k]<<endl;
	}
	return 0;
}

T4 避水珠

首先要观察出一个结论:虽然不限制玩家持有避水珠的数量,但出于最小化的角度考虑,任何时候玩家最多持有一个避水珠。

考虑DP。设状态为 d p [ i ] [ j ] dp[i][j] dp[i][j]表示在点 i i i处持有第j个避水珠时的最小能量消耗。其中 j = 0 j=0 j=0时表示不持有任何避水珠。

转移考虑下列情况:

  1. 当这段路不是雨区,可以不持有 dp\[i + 1\]\[0\] = min(dp\[i + 1\]\[0\], dp\[i\]\[j\])
  2. 当有一个避水珠时,可以保持 d p [ i + 1 ] [ j ] = m i n ( d p [ i + 1 ] [ j ] , d p [ i ] [ j ] + c o s t [ j ] ) dp[i + 1][j] = min(dp[i + 1][j], dp[i][j] + cost[j]) dp[i+1][j]=min(dp[i+1][j],dp[i][j]+cost[j])
  3. 如果这个位置有新的避水珠,可以换掉 d p [ i + 1 ] [ b i d [ i ] ] = m i n ( d p [ i + 1 ] [ b i d [ i ] ] , d p [ i ] [ j ] + c o s t [ b i d [ i ] ] ) dp[i + 1][bid[i]] = min(dp[i + 1][bid[i]], dp[i][j] + cost[bid[i]]) dp[i+1][bid[i]]=min(dp[i+1][bid[i]],dp[i][j]+cost[bid[i]]),其中 b i d [ i ] bid[i] bid[i]表示出现在点 i i i处的最小重量的避水珠编号。

最后在 d p [ a ] [ 1 ] dp[a][1] dp[a][1] ~ d p [ a ] [ m ] dp[a][m] dp[a][m] 之间取一个最小的答案即可。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e3 + 5;
const int INF = 0x3f3f3f3f;

int rain[maxn], bid[maxn], cost[maxn], dp[maxn][maxn];
int a, n, m;

int main() {
	cin >> a >> n >> m;
	for(int i = 1; i <= n; ++i) {
		int l, r; cin >> l >> r;
        ++rain[l]; --rain[r];
	}
    for(int i = 1;i <= a; ++i)
        rain[i] += rain[i - 1];
	
	for (int i = 1; i <= m; ++i) {
		int x, p; cin >> x >> p;
		cost[i] = p;
        if(bid[x] == 0 || cost[bid[x]] > p) 
            bid[x] = i;
	}
	memset(dp, 0x3f, sizeof dp);

    dp[0][0] = 0;
    for(int i = 0;i < a; ++i) {
        for(int j = 0;j <= m; ++j) {
            if(dp[i][j] == INF) continue;
            if(rain[i] == 0) dp[i + 1][0] = min(dp[i + 1][0], dp[i][j]);
            if(j) dp[i + 1][j] = min(dp[i + 1][j], dp[i][j] + cost[j]);
            if(bid[i]) dp[i + 1][bid[i]] = min(dp[i + 1][bid[i]], dp[i][j] + cost[bid[i]]);
        }
    }

	int ans = INF;
	for (int i = 0; i <= m; ++i)
		ans = min(ans, dp[a][i]);
	cout << ans << '\n';
	return 0;
}
相关推荐
爱思德学术6 分钟前
中国计算机学会(CCF)推荐学术会议-B(交叉/综合/新兴):BIBM 2025
算法
冰糖猕猴桃16 分钟前
【Python】进阶 - 数据结构与算法
开发语言·数据结构·python·算法·时间复杂度、空间复杂度·树、二叉树·堆、图
lifallen29 分钟前
Paimon vs. HBase:全链路开销对比
java·大数据·数据结构·数据库·算法·flink·hbase
liujing102329291 小时前
Day04_刷题niuke20250703
java·开发语言·算法
2401_881244402 小时前
Treap树
数据结构·算法
乌萨奇也要立志学C++2 小时前
二叉树OJ题(单值树、相同树、找子树、构建和遍历)
数据结构·算法
网安INF2 小时前
深度学习中的逻辑回归:从原理到Python实现
人工智能·python·深度学习·算法·逻辑回归
wsxqaz2 小时前
浏览器原生控件上传PDF导致hash值不同
算法·pdf·哈希算法
NAGNIP2 小时前
Transformer注意力机制——MHA&MQA&GQA
人工智能·算法
摘星编程3 小时前
多模态AI Agent技术栈解析:视觉-语言-决策融合的算法原理与实践
人工智能·算法·多模态ai·视觉语言融合·ai决策算法