QZEZ-csp-赛前模拟赛1

难度:普及(csp入门)

题面

QZEZOJ-csp-赛前模拟赛1-题面

T 1   M e s s a g e   R e l a y T_1\ Message\ Relay T1 Message Relay

解析

T 1 T_1 T1数据小,直接爆搜 (正解链式前向星

代码

#include<bits/stdc++.h>
using namespace std;
int N,a[1039],f[1039],ans;
bool q[1039];
bool find(bool s[],int n) {
	if(a[n]==1)return 1;
	if(s[n]||a[n]==-1)return 0;
	s[n]=1;
	return find(s,f[n]);
}
int main() {
	freopen("relay.in","r",stdin);
	freopen("relay.out","w",stdout);
	scanf("%d",&N);
	for(int i=1; i<=N; i++) {
		scanf("%d",&f[i]);
		if(f[i]==0) {
			ans++,a[i]=1;
		}
	}
	for(int i=1; i<=N; i++) {
		if(f[i]!=0) {
			memset(q,0,sizeof(q));
			if(find(q,i))ans++,a[i]=1;
			else a[i]=-1;
		}

	}
	printf("%d\n",ans);
}

T 2   01 数 字 排 序 T_2\ 01数字排序 T2 01

暂时未切,有DL会的话评论区见

T 3   P o k e r   H a n d s T_3\ Poker\ Hands T3 Poker Hands

暴力只有10分

思路

模拟一下数据
in 15 12 16 2 0 5 15 19
out 38
手从一个数开始推:

inout变化解析
1515//
15 1215//
15 12 1619+4第一个上升的点(12->16)
15 12 16 219//
15 12 16 2 019//
15 12 16 2 0 524+5再次上升(0->5)
15 12 16 2 0 5 1534+10同样上升(5->15)
15 12 16 2 0 5 15 1938+4仍上升(15->19)

可以发现是个线性DP

  • 上升的时候, a n s ans ans是上升的幅度
  • 下降时不变

代码

#include<bits/stdc++.h>
using namespace std;
long long N,a,an,ans,f;
bool y;
int main() {
	freopen("poker.in","r",stdin);
	freopen("poker.out","w",stdout);
	scanf("%d",&N);
	for(long long i=1; i<=N; i++){
		scanf("%lld",&a);
		if(f<a)ans+=a-f;
		f=a;
	}//f自己滚自己
	printf("%lld",ans);
	return 0;
} 

T 4   T h e   C o w   R u n T_4\ The\ Cow\ Run T4 The Cow Run

解析

一个有着无数细节的区间DP

DP状态设计

f i j f_{i}{}_{j} fij为第 i i i个数到第 j j j个数中间区间的最优值
然后因为要知道当前状态是从左边过来的还是右边过来的,所以要加一个0和1

DP递推式

D P = { f i   j   0 = min ⁡ ( f i + 1   j   0 + n u m i   j ∗ s i   i + 1 , f i + 1   j   1 + n u m i   j ∗ s i   j ) f i   j   1 = min ⁡ ( f i   j − 1   0 + n u m i   j ∗ s i   j , f i   j − 1   1 + n u m i   j ∗ s j − 1   j ) s i   j = ∣ p i − p j ∣ n u m i   j = n − j + i + 1 DP=\left\{ \begin{aligned} {f}_{i\ j\ 0} &= \min(f_{i+1\ j\ 0}+num_{i\ j}*s_{i\ i+1},f_{i+1\ j\ 1}+num_{i\ j}*s_{i\ j})\\ {f}_{i\ j\ 1} &=\min(f_{i\ j-1\ 0}+num_{i\ j}*s_{i\ j},f_{i\ j-1\ 1}+num_{i\ j}*s_{j-1\ j})\\ s_{i\ j} &=|p_i-p_j|\\ num_{i\ j}&= n-j+i+1\\ \end{aligned} \right. DP=fi j 0fi j 1si jnumi j=min(fi+1 j 0+numi jsi i+1,fi+1 j 1+numi jsi j)=min(fi j1 0+numi jsi j,fi j1 1+numi jsj1 j)=pipj=nj+i+1

无数的细节

  1. 初始值:在 f i   j   1 / 0 f_{i\ j\ 1/0} fi j 1/0 i > j i>j i>j是无意义的
  2. 无效区间:当 i > ( 原 点 在 的 位 置 ) i>(原点在的位置) i>() j < ( 原 点 在 的 位 置 ) j<(原点在的位置) j<()时,区间无意)
  3. 枚举方向: i   q → 0 i\ q\to0 i q0   \ {}   j   q → n j\ q\to n j qn (q为原点在的位置)

代码

#include<bits/stdc++.h>
using namespace std;
int N,a[1039],f[1039][1039][2],an,ans,s[1039][1039],q,Min=10000000;
int main() {
	freopen("cowrun.in","r",stdin);
	freopen("cowrun.out","w",stdout);
	scanf("%d",&N);
	for(int i=1; i<=N; i++) {
		scanf("%d",&a[i]);
	}memset(f,0x3f,sizeof(f));
	sort(a,a+1+N);
	for(int i=0;i<=N;i++){
		if(a[i]==0)q=i;
		for(int j=0;j<=N;j++){
			s[j][i]=abs(a[i]-a[j]);
		}
	}
	f[q][q][0]=f[q][q][1]=0;
	for(int i=q;i>=0;i--){
		for(int j=q;j<=N;j++){
			if(i==j)continue;
			f[i][j][0]=min(f[i+1][j][0]+(N-j+i+1)*s[i][i+1],f[i+1][j][1]+(N-j+i+1)*s[i][j]);
			f[i][j][1]=min(f[i][j-1][0]+(N-j+i+1)*s[i][j],f[i][j-1][1]+(N-j+i+1)*s[j-1][j]);
		}
	}
	printf("%d\n",min(f[0][N][1],f[0][N][0]));
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值