2019组队赛第三场(2017中国大学生程序设计竞赛 - 女生专场) 解题报告 Apare_xzc

2019组队赛第三场

2019/3/23

by xzc zx lj


vjudge链接:CCNUACM Team Contest 2019 Round #3

HDU链接:2017中国大学生程序设计竞赛 - 女生专场 (HDU6023-6032)

这场组队赛17级都是7题,18级都是4题(gdl:皆大欢喜)


A. Automatic Judge
题意:
模拟一个选手交题,返回结果有AC,CE,RE,WA…AC之前除了CE的未通过提交都算20minutes罚时,输入一个选手交题信息,求他的过题数和罚时
思路:
直接模拟即可
我们的代码<-戳这里


B. Building Shops
题意:
有n个教室(1<=n<=3000),要在这n个教室里面挑若干个建立商店。其中第i个城市的坐标为Xi,在第i个教室的位置上建商店的花费为Ci。(-1E9<=Xi,Ci<=1E9)
要保证对于每个教室,要么第在这个教室的位置有商店,要么这个教室左边的某个教室有商店。 在第i个教室建商店的费用为Ci,如果这个教室的位置没有建商店,那么这个教室的花费为它左边最靠近它的建了商店的教室和他的距离。求最小的花费。
分析:
把教室按Xi从小到大(从左到右)排序。显然第一个教室是一定要建商店的(因为它左边不可能有商店)。
我们一开始想贪心,后来发现贪心贪不对,只能dp

dp的思路:

  1. 对于每个教室来说,要么建商店,要么不建商店(除了第一个教室必须建)。
  2. 设dp[i][0]是第i个教室不建商店时前i个商店的总花费。设dp[i][1]是第i个教室建商店时前i个商店的花费之和
    那么我们就可以从左到右dp了。对于第i个教室
  3. 如果在这个教室建商店,那么前i个教室的最小花费就是前i-1个教室的最小花费加上Cidp[i][1] = min(dp[i-1][0],dp[i-1][1])+Ci
  4. 如果不在这个教室建商店,那么要从前i-1个建了商店的教室转移过来。但从哪个转移过来最优我们并不知道,所以要for一遍进行递推。设第i个教室左边最靠近它的教室是第j个(1<=j<=i-1),那么编号为j+1,j+2…i-1,i的教室都没有商店,都要靠教室j的商店供应。那么这些教室的花费为它们到教室j的距离之和。
    那么这个距离之和如何维护呢?我们想到了前缀和。我们设一个sum数组,记sum[i] = X1-X1+X2-X1+X3-X1+…+Xi-X1(前i个点到第一个教室的距离之和)
  5. 那么从j+1到第i个教室距离第j个教室距离之和可以表示为add(j,i) = sum[i]-sum[j]-(a[j]-a[1])*(i-j)
    dp[i][0] = min(dp[j][1]+add(j,i) (j<i)
  6. 初始化: dp[1][0] = INF, dp[1][1] = C1
//转移方程
For(i,2,n)
{
    dp[i][1] = min(dp[i-1][0],dp[i-1][1])+a[i].c; 
    For(j,1,i-1)
        LL add = sum[i]-sum[j]-(a[j].x-a[1].x)*(1ll*i-j),
        dp[i][0] = min(dp[i][0],dp[j][1]+add);
}

我们的代码


C. Coprime Sequence(FB)
题意:
给n个数(3<=n<=1E5)a1,a2,a3…an,这些数的gcd为1,现在可以从这些数之中随便删去一个。使得剩下的数的gcd最大,求这个最大的gcd。
分析:
zx想的前缀和与后缀和:
sumL = gcd(a[1],a[2],…,a[i])
sumR = gcd(a[n],a[n-1],…,a[i])
设要删除的数为a[i],那么删掉后数列的gcd为gcd(sumL[i-1],sumR[i+1]) 然后for一遍即可。一血(^_^)

我们的代码


D. Deleting Edges
题意:
给一个n(n<=50)个顶点的图的邻接矩阵,求从顶点0到其它所有顶点的最短路径的条数的乘积
分析:
两次Dijkstra,第一次求最短路,第二次求原点到各个点最短路的条数(每次松弛操作时,若能松弛,则num[i]++)
我们的代码


E. Easy Summation(FB)
题意:
求1^k + 2^k + … + n^k之和(k<=5)
分析:
暴力求即可,签到题,一血。^_^

我们的代码


G. Graph Theory
题意:
这道题是给出一个图,问是否能满足“perfect matching”——每个顶点与且只与一条边相连。
分析:
一开始读错题WA了两发,做法是:

  • n为奇数时必然不能两两配对,输出No;
  • 否则,从后往前扫,若当前结点操作为1,则记录1操作的数量加一
  • 否则减一,当遍历到1操作的数量不够匹配当前操作为2的结点时则输出No。
  • 为什么要从后往前扫呢?因为越靠后的数操作为1时选择匹配操作2的结点范围越大,也避免了单纯考虑两操作数量而忽略“操作1后存在操作2”及“末尾多个操作1”的情况,如122、211。

我们的代码


H. Happy Necklace
题意:
要做一个长度为n(n<=1E18)的手链(不是环),每个单位长度可以是蓝宝石或者红宝石。但是要求每个长度为素数的区间红宝石数量不少于蓝宝石。求满足条件的手链的个数%1000000007
分析:
这么大的数,是矩阵快速幂无疑了(矩阵快速幂加速dp)
我们来推递推式吧

  • 首先,2和3都是素数,要满足长度为2和3的区间都红>=蓝,那么肯定不能有两个连续的蓝(BB),也不能有蓝红蓝(BRB)。
  • 我们发现如果满足了长为2和3的区间,那么5也满足,7也满足…
  • 所以我们只需要保证长度为2和3的区间满足num®>=num(B)即可
  • 分析过后,我们发现因为不能出现BB这样的两个蓝色相邻的情况,所以连续的两个只能是RR,RB,BR,我们设为状态0,1,2
  • 那么RR可以从BR和RR转移过来,RB只能从RR转移过来,BR只能从RB转移而来
状态定义:末两位的颜色
RR: 0
RB: 1
BR: 2
转移方程:
RR: dp[i][0] = dp[i-1][0]+dp[i-1][2] 
RB: dp[i][1] = dp[i-1][0] 
BR: dp[i][2] = dp[i-1][1] 

递推式的矩阵表示:
|dp[i][0]|   |1,0,1|     |dp[i-1][0]|
|dp[i][1]| = |1,0,0|  *  |dp[i-1][1]|
|dp[i][2]|   |0,1,0|     |dp[i-1][2]|

|dp[n][0]|   |1,0,1|          |dp[2][0]|(1)
|dp[n][1]| = |1,0,0| ^(n-2) * |dp[2][1]|(1)
|dp[n][2]|   |0,1,0|          |dp[2][2]|(1)
perfect!

我们的代码


猜你喜欢

转载自blog.csdn.net/qq_40531479/article/details/88983412