2019.01.31【NOIP提高组】模拟 B 组

111 篇文章 0 订阅
99 篇文章 1 订阅

JZOJ 4255 ACM

题目

在一开始,队伍的每一个人会评估每一道题的难度,难度会用1~5的整数表示,数字越大题目越难。然后他们会分配题目给每个人。题目会分成三个部分,每个队员会拿到一个非空的连续的题目代表了他要解决的问题。他们的策略是让难度评估系数最小。难度评估系数是三个队员对各自所拿到题目的难度评估的总和。你的任务是计算这个最小的难度评估系数。


分析

那么这道题数据有点水,于是我用了个贪心也能AC,不过这道题正解应该是动态规划,其实也很容易想,设 d p [ n ] [ 1 ∼ 3 ] dp[n][1\sim 3] dp[n][13]表示前 n n n个题分到第 1 ∼ 3 1\sim 3 13部分所得到胡最小难度评估系数,那么 d p [ n ] [ 1 ] = d p [ n − 1 ] [ 1 ] + a [ n ] , d p [ n ] [ 2 ∼ 3 ] = m i n { d p [ n − 1 ] [ 1 ∼ 2 ] , d p [ n − 1 ] [ 2 ∼ 3 ] } + a [ n ] dp[n][1]=dp[n-1][1]+a[n],dp[n][2\sim3]=min\{dp[n-1][1\sim 2],dp[n-1][2\sim 3]\}+a[n] dp[n][1]=dp[n1][1]+a[n],dp[n][23]=min{dp[n1][12],dp[n1][23]}+a[n]


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=150011;
int n,ans,a[N],b[N],c[N],dp1[N],dp2[N],dp3[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void answ(int *a,int *b,int *c){
	memset(dp1,127/3,sizeof(dp1));
	memset(dp2,127/3,sizeof(dp2));
	memset(dp3,127/3,sizeof(dp3));
	dp1[1]=a[1];
	for (rr int i=2;i<=n;++i){
		dp1[i]=dp1[i-1]+a[i];
		dp2[i]=min(dp1[i-1],dp2[i-1])+b[i];
		dp3[i]=min(dp2[i-1],dp3[i-1])+c[i];
	}
	ans=min(ans,dp3[n]);
}
signed main(){
	freopen("acm.in","r",stdin);
	freopen("acm.out","w",stdout);
	n=iut(); ans=2147483647;
	for (rr int i=1;i<=n;++i) a[i]=iut();
	for (rr int i=1;i<=n;++i) b[i]=iut();
	for (rr int i=1;i<=n;++i) c[i]=iut();
	answ(a,b,c),answ(a,c,b),answ(b,a,c),answ(b,c,a),answ(c,a,b),answ(c,b,a);
	return !printf("%d",ans);
}

JZOJ 4256 平均数

题目

给出包含一个 N N N个整数的数组 A A A。找出一段长度至少为 K K K的连续序列,最大化它的平均值。


分析

那么这道题可以转换为二分它的平均值,判定是否非负,那么这样就比较简单了,不过数据还是有点水分,我自己做的程序被自己做的数据HACK掉了


代码

#include <cstdio>
#include <deque>
#include <cctype>
#define rr register
using namespace std;
int n,k,a[300001];
double now[300001];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
signed main(){
	freopen("average.in","r",stdin);
	freopen("average.out","w",stdout);
	n=iut(); k=iut();
	for (rr int i=1;i<=n;++i) a[i]=iut();
	rr double l=1,r=1e6;
	while (l+1e-8<r){
		rr double mid=(l+r)/2,ans,minn=0;
		for (rr int i=1;i<=n;++i) now[i]=now[i-1]+a[i]-mid; ans=now[k];
		for (rr int i=1;i<=n-k;++i){
		    minn=min(minn,now[i]);
			ans=max(ans,now[i+k]-minn);
		}
		if (ans>=0) l=mid; else r=mid;
	}
	return !printf("%.8lf",l);
} 

JZOJ 4257 着色

题目

在一个图中用最多3种颜料(共有 M M M种颜料)涂色,使相邻两个区域不同色


分析

首先 m = 1 m=1 m=1是一定不可能的
一共有8个图,24个测试点
第一个图:在这里插入图片描述
首先在 m m m种颜色选择3种,那么就是 c ( m , 3 ) c(m,3) c(m,3),如果头可以选3种,那么其它地方只能选两种,也就是 c ( m , 3 ) × 3 × 2 19 c(m,3)\times3\times2^{19} c(m,3)×3×219,化简得到 m × ( m − 1 ) × ( m − 2 ) × 2 18 m\times(m-1)\times(m-2)\times2^{18} m×(m1)×(m2)×218,如果你是这么想的,恭喜你没分了,那么为什么会错呢,因为算重了在这三种只选了两种 P ( 3 , 2 ) P(3,2) P(3,2)的情况,那么应该为 m × ( m − 1 ) + m × ( m − 1 ) × ( m − 2 ) × ( 2 18 − 1 ) m\times(m-1)+m\times(m-1)\times(m-2)\times(2^{18}-1) m×(m1)+m×(m1)×(m2)×(2181)
第二个图:
在这里插入图片描述
那么这道题只能有三种颜色,所以不需要考虑是否算重,那么设大长方形的可选种类有 m m m种,那么分别为
在这里插入图片描述
那么答案就是 c ( m , 3 ) × 3 × 2 5 = m × ( m − 1 ) × ( m − 2 ) × 16 c(m,3)\times 3\times 2^5=m\times(m-1)\times(m-2)\times16 c(m,3)×3×25=m×(m1)×(m2)×16
第三个图:
在这里插入图片描述
那么显而易见答案就是 m × ( m − 1 ) × ( m − 2 ) × 4 m\times(m-1)\times(m-2)\times 4 m×(m1)×(m2)×4
但是答案还是错了,和第一个图类似,必须去掉重复的答案
所以应该是 m × ( m − 1 ) + m × ( m − 1 ) × ( m − 2 ) × 3 m\times(m-1)+m\times(m-1)\times(m-2)\times3 m×(m1)+m×(m1)×(m2)×3
下同,所以不写了


代码

#include <cstdio>
#define rr register
using namespace std;
typedef long long ll;
ll q,m,ans;
signed main(){
	freopen("color.in","r",stdin);
	freopen("color.out","w",stdout);
	scanf("%lld%lld",&q,&m);
	if (m==1) return !printf("0");
	if (q==1){
		if (m==2) ans=2;
		else ans=m*(m-1)+m*(m-1)*(m-2)*((1<<18)-1);
	}
	else if (q==8){
		if (m==2) ans=2;
		else ans=m*(m-1)+m*(m-1)*(m-2)*((1<<29)-2)/3;
	}
	else if (q==5){
		if (m==2) ans=0;
		else ans=m*(m-1)*(m-2)<<1;
	}
	else if (q==2||q==7){
		if (m==2) ans=0;
		else ans=m*(m-1)*(m-2)<<4;
	}
	else if (q==3){
		if (m==2) ans=2;
		else ans=m*(m-1)+m*(m-1)*(m-2)*3;
	}
	else if (q==4){
		if (m==2) ans=2;
		else ans=m*(m-1)+m*(m-1)*(m-2)*((1<<12)-1);
	}
	else if (q==6){
		if (m==2) ans=0;
		else ans=m*(m-1)*(m-2);
	}
	return !printf("%lld",ans);
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值