• six


    7月12日

    1.classic

    总时间限制:

    20000ms

    内存限制:

    256000kB

    描述

    今天讲的数据结构题在后面。

    Classic是一个极富创意的成果。

    还记得我曾经给你们讲过的东西吗?

    求L到R之间各位数字和在x到y之间的数的和对1,000,000,007取模的值。

     

    输入

    第一行一个整数L。
    第二行一个整数R。
    第三行两个整数x、y。

    输出

    一行一个整数代表答案。

    样例输入

    1

    100

    4 13

    样例输出

    3575

    提示

    对于30%的数据,0≤L≤R≤10^3。
    对于50%的数据,0≤L≤R≤10^9。
    对于80%的数据,0≤L≤R≤10^18。
    对于100%的数据,0≤L≤R≤10^50,0≤x≤y≤500。

     

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #define PROC "classic"
    #define LL long long 
    using namespace std;
    const int maxlen = 70;
    const int maxsum = 505;
    const LL mo =  1000000007;
    LL cnt[maxlen][maxsum][2]; 
    LL dp[maxlen][maxsum][2];
    int l[maxlen],r[maxlen],lenl,lenr,x,y;
    long long deal(int now[maxlen],int len)
    {    
             LL ans = 0;
         memset(cnt,0,sizeof(cnt));
         memset(dp,0,sizeof(dp));
            for (int i = 0;i<now[1];i++)
             cnt[1][i][0] = 1,dp[1][i][0] = i % mo;
             cnt[1][now[1]][1] = 1,dp[1][now[1]][1] = now[1] % mo;
            int nowsum = 0;
            for (int i = 1;i<len;i++)
         {
               nowsum +=now[i];
               for (int k = 0;k<=i*9;k++)
               for (int j = 0;j<10;j++)
                   cnt[i+1][k+j][0]=(cnt[i+1][k+j][0] % mo+cnt[i][k][0] % mo) % mo;
               for (int j = 0;j<now[i+1];j++)
               cnt[i+1][nowsum+j][0]=(cnt[i+1][nowsum+j][0] % mo+cnt[i][nowsum][1]) % mo;
               cnt[i+1][nowsum+now[i+1]][1]=(cnt[i+1][nowsum+now[i+1]][1] % mo+cnt[i][nowsum][1]) % mo;
              }
            nowsum = 0;
            for (int i = 1;i<len;i++)
            {
                   nowsum +=now[i];
             for (int k = 0;k<=9*i;k++)
              for (int j = 0;j<=9;j++)
               dp[i+1][k+j][0]=(dp[i+1][k+j][0] % mo+((LL)dp[i][k][0]*10 % mo + j*cnt[i][k][0]%mo) % mo) % mo;
              for (int j = 0;j<now[i+1];j++)
               dp[i+1][nowsum+j][0]=(dp[i+1][nowsum+j][0]% mo+((LL)dp[i][nowsum][1]*10%mo+j)%mo) % mo;
               dp[i+1][nowsum+now[i+1]][1]=(dp[i+1][nowsum+now[i+1]][1] % mo+(LL)(dp[i][nowsum][1]*10%mo+now[i+1]) % mo)% mo;
            }  
         for (int i = x;i<=y;i++)
             ans +=(dp[len][i][0]%mo + dp[len][i][1]%mo)%mo;
             return ans%mo;
    }
    int main()
    {
            char ch;
            LL sumwei = 0,sum = 0;
            ch = getchar();
        while (ch!='
    ')
        {
                   l[++lenl] = (int)(ch - '0');
                   sumwei+=l[lenl];
                ch = getchar();
            }
            ch = getchar();
             while (ch!='
    ')
        {
                   r[++lenr] = (int)(ch - '0');
                ch = getchar();
            }
            scanf("%d%d",&x,&y);
            LL ans1 = deal(l,lenl),ans2 = deal(r,lenr);
            if (sumwei>=x && sumwei<=y) 
             for (int i = 1;i<=lenl;i++)
              sum = (sum*10+l[i]) %mo;
            cout<<((ans2 - ans1+sum)%mo+mo)%mo;
            return 0;
    }

    正解:做时大体思路即正解。

    做:还是费了两小时,大抵是担心写错,因而很慢,战战兢兢。

    简单数位dp

    Cnt[i][j][k]表示从最高位为1计起,至第i位数位和为j时,抵上界(k=1)|未抵上界(k=0)的数的个数。

    Dp[i][j][k]字母含义同cnt,但是记录当前满足条件数之和。

    由此写出方程即可求解。

    主要错因(从AC到WA 10):检查代码时发现l木有-1,于是添上,殊不知l是数组,怎能如此作为。

     

    改:本人不才,若代码看上去繁杂即是修改半小时,加了无数(% mo) 的结果,这也说明数据规模的重要性,凿凿的“wa”希望能带给自己思考——严谨。另外对于删去l的处理思虑很久,最终选择特别计算l,判断满足条件否进行结果的修改,后来发现标称亦是如此,更是警醒自己要深思熟虑才可着手去做。

    得:数据类型毁终生

    2.justice

    总时间限制:

    25000ms

    内存限制:

    256000kB

    描述

    还在后面一些。

    Justice是少见的一款长篇。

    求1-N的第K短路。(非严格,详见样例)

     

    输入

    第一行两个整数N、M、K代表图的点数、边数和要求的K。
    接下来M行,每行三个整数S、E、D,代表S与E之间有一条长度为D的无向边。

    输出

    一行一个整数代表第K短路。

    样例输入

    【样例输入1】

    2 1 2

    1 2 1

    【样例输入2】

    2 2 2

    1 2 1

    1 2 1

    样例输出

    【样例输出1】

    3

    【样例输出2】

    1

    提示

    对于20%的数据,1≤N,M≤10^2。
    对于另外30%的数据,K=1。
    对于另外20%的数据,K=2。
    对于100%的数据,1≤N,M≤10^5,1≤K≤20,边的权值在103以内。

     

    #include<cstdio>

    #include<iostream>

    #include<cstring>

    using namespace std;

    const int MAXN = 100005;

    const int MAXK = 21;

    int dis[MAXN][MAXK],n,m,k,ne;

    int q1[MAXN * MAXK],q2[MAXN * MAXK];

    bool in[MAXN][MAXK];

    struct Edge

    {

            int f,t,d;

            Edge * next;

    } e[MAXN * 2],* head[MAXN];

    void addedge(int f,int t,int d)

    {

            e[++ne].t = t;

            e[ne].d = d;

            e[ne].next = head[f];

            head[f] = e + ne;

    }

    void spfa(int x)

    {

            int l = 1,r = 1;

            dis[x][0] = 0;

            q1[r] = x;

            q2[r] = 0;

            r++;

            if (r==n * k) r = 0;

            in[x][0] = true;

            while (r-l)

            {

                   int now = q1[l];

                   int kth = q2[l];

                   l++;

                   if (l==n * k) l = 0;

                   in[now][kth] = false;

                   for (Edge * p = head[now];p;p=p->next)

                   {

                           int t = p->t;

                           int newd = dis[now][kth];

                            for (int i = 0;i<k;i++)  

                            if (dis[t][i] > newd + p->d)

                            {

                                          for (int j = k-1;j>i;j--)

                                           dis[t][j] = dis[t][j-1];

                                          dis[t][i] = newd + p->d;

                                                                                for (int w = i;w<k;w++)

                                          if (!in[t][w])

                                          {

                                                  q1[r] = t;

                                                  q2[r] = w;

                                                  r++;                                          if (r==n * k) r=0;

                                                  in[t][w] = true;

                                          }

                                          break;

                            }

                   }

            }

           

    }

    int main()

    {

            scanf("%d%d%d",&n,&m,&k);

            int f,t,d;

            for (int i = 1;i<=m;i++)

        {

                   scanf("%d%d%d",&f,&t,&d);

                   addedge(f,t,d);

                   addedge(t,f,d);

            }

            memset(in,false,sizeof(in));

            memset(dis,0x3f3f,sizeof(dis));

            spfa(1);

            printf("%d",dis[n][k-1]);

            return 0;

    }

    正解:这是一道极好的题目

    基本思路仍然是最短路,着手修改过程,找最短路无非就是逐渐更新的过程,

    倘若记录下所有更新的节点及更新的路的排名,并用改更新的点去继续更新所有与之相连点的上述两个变量,即可求出the Kth shortest road

    因此队列需要两个,相辅相成,齐头并进。

    更新一个点也变成了更新一整行(即该点编号所在的记录最短路排名的那一行(in【定点】【0~k-1】))

    做:被样例一吓到了,没有考虑到每一个点都有最短路排名,包括起点。

    改:1.没有机智地想到用两个队列来记录,因此在以一个点去更新另一个点时有小纠结。

       2.所有更新的点,包括同一个点的多条路径排名都需要加入队列。

    得:对于已知的算法绝不满足 对基本算法理解不深呐~~~~

  • 相关阅读:
    scala环境配置+hello world!
    mysql无法登录
    ajax跨域
    jfinal框架页面找不到相关css,js文件404
    从程序员到CTO的Java技术路线图 作者:zz563143188
    在項目中快速部署SLF4J+LOGBACK
    Spring整合MyBatis
    SpringMVC常用注解實例詳解3:@ResponseBody
    浏览器包含哪些进程?
    前端程序员也需要知道进程和线程
  • 原文地址:https://www.cnblogs.com/rubylan/p/3840454.html
Copyright © 2020-2023  润新知