郑州大学2018新生训练赛第十场题解

  比赛(补题)地址:http://222.22.65.164/problemset.php

  题号为:4305 —— 4309

  总述:这次新生赛难度偏于平和,但涵盖方面甚广,其中一道签到题是c语言题,并且有两道是hdu一百题的原题,一道简单的最小生成树,唯一“有些难度”的应该是一道数论题(毕竟本来自己就是搞数学的)。

   A.沙漠骆驼

      

      

  这是一道经典的递推问题,原型为HDU 2044的“一只小蜜蜂…”。思路很简单,以第5个沙丘为例,到达第五个沙丘的方式有两种:从第3个向 右走,或从第4个向右上走。设dp[ i ]为从第一个沙丘走到第i个的路径数,我们容易得到递推方程:

                    dp[5] = dp[4] + dp[3]

  那么依此类推,得到一般的递推方程:

                    dp[ i ] = dp[ i-1 ] + dp[ i-2 ]

  而从第a个到第b个,则可以简化为第1个到第b-a个。

        

 1 ll f[100];
 2
 3 void init() {
 4     f[1] = f[2] = 1;
 5     for (int i = 3; i < 100; i++) {
 6         f[i] = f[i - 1] + f[i - 2];
 7     }
 8 }
 9
10 int main() {
11     init();
12
13     int t;
14     scanf("%d", &t);
15     int a, b;
16     while (t--) {
17         scanf("%d%d", &a, &b);
18         printf("%lld\n", f[b - a + 1]);
19     }
20
21     return 0;
22 }

  B.炉石传说真好玩!

  水题,原题是 HDU 2052 的 “Picture”,直接放代码:

 1 int main() {
 2     int n, m;
 3     while (~scanf("%d%d", &n, &m)) {
 4         putchar(‘+‘);
 5         for (int i = 0; i < n; i++) putchar(‘-‘);
 6         putchar(‘+‘);
 7         putchar(‘\n‘);
 8         for (int i = 0; i < m; i++) {
 9             putchar(‘|‘);
10             for (int j = 0; j < n; j++) {
11                 putchar(‘ ‘);
12             }
13             putchar(‘|‘);
14             putchar(‘\n‘);
15         }
16         putchar(‘+‘);
17         for (int i = 0; i < n; i++) putchar(‘-‘);
18         putchar(‘+‘);
19         putchar(‘\n‘);
20         putchar(‘\n‘);
21     }
22
23     return 0;
24 }

  C.加油啊!奥托大人!

  Emmm,这是一道裸的Kruskal,不理解的大家可以搜索一下,不想搜的也可以等数据结构老师讲,2333.

  这道题的原题是 HDU 1863 的 “ 畅通工程”。

  代码如下:

 1 struct Edge {
 2     int from, to, w;
 3
 4     Edge(int from = 0, int to = 0, int w = 0):
 5     from(from), to(to), w(w) {}
 6
 7     bool operator < (const Edge &rhs) const {
 8         return w < rhs.w;
 9     }
10 } edge[MAXEDGE];
11
12 int parents[MAXVERTEX];
13 int vertices, edges;
14
15 void init() {
16     for (int i = 1; i < MAXVERTEX; i++) {
17         parents[i] = i;
18     }
19 }
20
21 int find(int x) {
22     if (parents[x] == x) {
23         return x;
24     } else {
25         return parents[x] = find(parents[x]);
26     }
27 }
28
29 bool unite(int x, int y) {
30     x = find(x);
31     y = find(y);
32     if (x == y) {
33         return true;
34     } else {
35         parents[y] = x;
36     }
37     return false;
38 }
39
40 int kruskal() {
41     init();
42     sort(edge, edge + edges);
43     int ans = 0, counter = 1;
44     for (int i = 0; i < edges; i++) {
45         if (unite(edge[i].from, edge[i].to)) {
46             continue;
47         } else {
48             ans += edge[i].w;
49             counter++;
50         }
51         if (counter >= vertices) {
52             break;
53         }
54     }
55     if (counter >= vertices) {
56         return ans;
57     } else {
58         return -1;
59     }
60 }
61
62 int main() {
63     int u, v, w;
64
65     while (~scanf("%d%d", &edges, &vertices)) {
66         if (edges == 0) break;
67         for (int i = 0; i < edges; i++) {
68             scanf("%d%d%d", &u, &v, &w);
69             edge[i] = Edge(u, v, w);
70         }
71
72         int ans = kruskal();
73         if (ans == -1) {
74             printf("?\n");
75         } else {
76             printf("%d\n", ans);
77         }
78     }
79
80     return 0;
81 }

 

  D.大家快来%啊!

  这。。。签到题就不用讲,也不用放代码了吧。

  唯一需要注意的是纯c选手输出时需要将%转义。

    

  E.R.I.P.

  根据算数基本定理,任何一个自然数都可以唯一地分解为若干个素数的乘积,如果我们列出这个数所有的质因数,并写成幂的乘积的形式,则称其为标准素因数分解式

  比如:对于120,120 = 2*2*2*3*5,写成标准素因数分解式就是:

                    120 = 2* 31 * 51

  那么我们就可以轻易地得到 120 因子个数:所有幂次+1的乘积 

  也就是:                                       ( 3 + 1 ) * ( 1 + 1 ) * ( 1 + 1 ) = 16  

  .....在此证明过程不再赘述 

  知道了这些,我们来考虑让一个数因子个数扩大到二倍(我们称其为一次“扩展”)的 “ 费用 ” :

  我们可以将总的费用写为素因子幂的乘积的形式。

  考虑这样实现:将总费用维护为一个堆(为什么要维护成堆?请认真思考),每个素因子的费用都保存在一个含有“ 底数,指数,值 ”的结构体中。

  初始时堆中没有元素,通过不断进行“ 扩展 ”,逐渐向堆中增加元素,直到因子个数符合要求(500500)。

  那么 最后每一个结构体中的值再除以底数(为什么要除以底数?请认真思考) 的乘积就是总的费用。

  在考虑操作方法,不外乎有两种:

    1、扩展一个新的(指数为0)的素因子(比如说取了 2),并标记为“新素数”(以待后用)。

      同时对这个素因子的费用进行更新 2(0+1)->(1 + 1)           

    2、在堆中取扩展费用最小的素数,进行扩展(更新其指数),同时更新其费用。

      如果这个素数是一个“新素数”,那么我们从打好的素数表中,取下一个素数(比如说取了2)进堆,将其指数初始化为0

  下边来看一下代码实现:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 int MAXN=600000,curnum=0;
 5 bool vis[10000000];
 6 vector<int> sushu;
 7 int cursushu=0;
 8 struct node{
 9     int dishu;
10     int zhishu;
11     ll zhi;
12
13 };
14 bool operator<(node a,node b)
15 {
16     return a.zhi>b.zhi;
17 }
18
19 priority_queue<node> dui;
20 ll ans=1;
21
22 void dabiao(){
23     for(ll i=2;;i++){
24         if(!vis[i]){
25             sushu.push_back(i);
26         }
27         if(sushu.size()>500500){
28             break;
29         }
30         for(ll j=i*i;j<10000000;j+=i){
31             vis[j]=true;
32         }
33     }
34 }
35 void addnew(int x){
36     node p;
37     p.dishu=sushu[x];
38     p.zhishu=1;
39     p.zhi=p.dishu;
40     dui.push(p);
41 }
42
43
44 void update_old_node(node tmp){
45     node a;
46     a.dishu=tmp.dishu;
47     a.zhishu=tmp.zhishu*2;
48     a.zhi=1;
49     for(int i=0;i<a.zhishu;i++){
50         a.zhi*=a.dishu;
51     }
52     dui.push(a);
53 }
54
55 void act(){
56     node tmp=dui.top();
57     dui.pop();
58     if(tmp.dishu==sushu[cursushu-1]){
59         addnew(cursushu++);
60         update_old_node(tmp);
61     }
62     else{
63         update_old_node(tmp);
64     }
65 }
66
67 int main()
68 {
69     cout<<"Input N:"<<endl;
70     int n;
71     cin>>n;
72     dabiao();
73     addnew(cursushu++);
74     for(int i=0;i<n;i++)
75         act();
76     while(!dui.empty()){
77         ans*=(dui.top().zhi/dui.top().dishu%500500507);
78         ans%=500500507;
79         dui.pop();
80     }
81     cout<<ans;
82 }

   更新得这么迟实在不好意思,抱歉耽误大家时间了,QAQ!

原文地址:https://www.cnblogs.com/moonfair/p/9976155.html

时间: 2024-11-05 19:33:56

郑州大学2018新生训练赛第十场题解的相关文章

2018-2019赛季多校联合新生训练赛第六场(2018/12/15)补题题解

A 价钱统计(基础编程能力) 这个考点还是比较个性的,怎么四舍五入 解法 常规的讲如果四舍五入整数位的话,那么只需要在后面加个0.5然后强制转换一下就可以了 这个却要我们保留一位小数的四舍五入,那该怎么做呢 实际上我们只需要把这个数乘以10然后加0.5,强制转换后再除以10就可以了 代码 #include <bits/stdc++.h> using namespace std; double trans(double a) { a*=10; a+=0.5; a=int(a); a/=10; r

2018-2019赛季多校联合新生训练赛第八场(2018/12/22)补题题解

感慨 这次有点感冒,昏迷程度比较大中途还溜了 感谢 感谢qut的同学的帮助!!! A 小X与三角形(数学) 公式 两边的和-两边的差-1 因为边最小得大于两边的差,边最大得小于两边的和所以说求得是一个开区间内元素的个数 代码 #include <bits/stdc++.h> using namespace std; typedef long long ll; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); ll a,

Contest1657 - 2019年我能变强组队训练赛第十四场

Contest1657 - 2019年我能变强组队训练赛第十四场 Similarity of Subtrees #include <bits/stdc++.h> using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxn=100100; ull ha[maxn]; vector<int>E[maxn]; unordered_map<ull,int>m;

1780 - 2019年我能变强组队训练赛第十八场

题目描述 wls有一个钟表,当前钟表指向了某一个时间. 又有一些很重要的时刻,wls想要在钟表上复现这些时间(并不需要依次复现).我们可以顺时针转动秒针,也可以逆时针转动秒针,分针和时针都会随着秒针按规则转动,wls想知道秒针至少转动多少角度可以使每个时刻至少都会被访问一次. 注意,时钟上的一种时针分针秒针的组合,可以代表两个不同的时间. 输入 第一行一个整数n代表有多少个时刻要访问. 第二行三个整数h,m,s分别代表当前时刻的时分秒. 最后n行每一行三个整数hi,mi,si代表每个要访问的时刻

HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&#39;s problem(manacher+二分/枚举)

HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分相同,第一部分与第二部分对称. 现在给你一个长为n(n<10^5)的序列,求出该序列中N序列的最大长度. 思路: 来自官方题解:修正了一些题解错别字(误 先用求回文串的Manacher算法,求出以第i个点为中心的回文串长度,记录到数组p中 要满足题目所要求的内容,需要使得两个相邻的回文串,共享中间的一部分,也就是说,左边的回文串长度的一半,要大于等于共享部分的长度,右边回文串也是一样. 因为我们已经记录下来以

HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&amp;#39;s problem(manacher+二分/枚举)

pid=5371">HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分同样,第一部分与第二部分对称. 如今给你一个长为n(n<10^5)的序列,求出该序列中N序列的最大长度. 思路: 来自官方题解:修正了一些题解错别字(误 先用求回文串的Manacher算法.求出以第i个点为中心的回文串长度.记录到数组p中 要满足题目所要求的内容.须要使得两个相邻的回文串,共享中间的一部分,也就是说.左边的回文串长度的一半,要大于等于共享部分的长度,右边回文串也

HDU 4902 Nice boat 2014杭电多校训练赛第四场F题(线段树区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4902 解题报告:输入一个序列,然后有q次操作,操作有两种,第一种是把区间 (l,r) 变成x,第二种是把区间 (l,r) 中大于x的数跟 x 做gcd操作. 线段树区间更新的题目,每个节点保存一个最大和最小值,当该节点的最大值和最小值相等的时候表示这个区间所有的数字都是相同的,可以直接对这个区间进行1或2操作, 进行1操作时,当还没有到达要操作的区间但已经出现了节点的最大值跟最小值相等的情况时,说明

HDU 4941 Magical Forest(map映射+二分查找)杭电多校训练赛第七场1007

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4941 解题报告:给你一个n*m的矩阵,矩阵的一些方格中有水果,每个水果有一个能量值,现在有三种操作,第一种是行交换操作,就是把矩阵的两行进行交换,另一种是列交换操作,注意两种操作都要求行或列至少要有一个水果,第三种操作是查找,询问第A行B列的水果的能量值,如果查询的位置没有水果,则输出0. 因为n和m都很大,达到了2*10^9,但水果最多一共只有10^5个,我的做法是直接用结构体存了之后排序,然后m

【杂题总汇】HDU多校赛第十场 Videos

[HDU2018多校赛第十场]Videos 最后一场比赛也结束了-- +HDU传送门+ ◇ 题目 <简要翻译> 有n个人以及m部电影,每个人都有一个快乐值.每场电影都有它的开始.结束时间和看了这部电影会得到的快乐值.电影分成两种类型,若同一个人连续(不是时间连续,是顺序连续)看了两部相同类型的电影,他的快乐值会扣除W,数据保证扣除的值不超过电影增加的快乐值. 特别的,一个人换电影不花费时间,即若第一部电影的结束时间等于下一部电影的开始时间,是可以两场都看的:看电影必须看完:一部电影只能一个人看