zoukankan      html  css  js  c++  java
  • 郑州大学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
    ", 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('
    ');
     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('
    ');
    15         }
    16         putchar('+');
    17         for (int i = 0; i < n; i++) putchar('-');
    18         putchar('+');
    19         putchar('
    ');
    20         putchar('
    ');
    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("?
    ");
    75         } else {
    76             printf("%d
    ", 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!

  • 相关阅读:
    五一训练礼包 — B
    五一训练礼包—坐标问题
    单链表
    顺序表
    链表
    基础DP(3)
    基础DP(2)
    基础DP(1)
    分治法
    最小表示法
  • 原文地址:https://www.cnblogs.com/moonfair/p/9976155.html
Copyright © 2011-2022 走看看