JZOJ 4255 ACM
题目
在一开始,队伍的每一个人会评估每一道题的难度,难度会用1~5的整数表示,数字越大题目越难。然后他们会分配题目给每个人。题目会分成三个部分,每个队员会拿到一个非空的连续的题目代表了他要解决的问题。他们的策略是让难度评估系数最小。难度评估系数是三个队员对各自所拿到题目的难度评估的总和。你的任务是计算这个最小的难度评估系数。
分析
那么这道题数据有点水,于是我用了个贪心也能AC,不过这道题正解应该是动态规划,其实也很容易想,设 d p [ n ] [ 1 ∼ 3 ] dp[n][1\sim 3] dp[n][1∼3]表示前 n n n个题分到第 1 ∼ 3 1\sim 3 1∼3部分所得到胡最小难度评估系数,那么 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[n−1][1]+a[n],dp[n][2∼3]=min{dp[n−1][1∼2],dp[n−1][2∼3]}+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×(m−1)×(m−2)×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×(m−1)+m×(m−1)×(m−2)×(218−1)
第二个图:
那么这道题只能有三种颜色,所以不需要考虑是否算重,那么设大长方形的可选种类有
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×(m−1)×(m−2)×16
第三个图:
那么显而易见答案就是
m
×
(
m
−
1
)
×
(
m
−
2
)
×
4
m\times(m-1)\times(m-2)\times 4
m×(m−1)×(m−2)×4
但是答案还是错了,和第一个图类似,必须去掉重复的答案
所以应该是
m
×
(
m
−
1
)
+
m
×
(
m
−
1
)
×
(
m
−
2
)
×
3
m\times(m-1)+m\times(m-1)\times(m-2)\times3
m×(m−1)+m×(m−1)×(m−2)×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);
}