zoukankan      html  css  js  c++  java
  • [SinGuLaRiTy] 2017 百度之星程序设计大赛 复赛

    【SinGuLaRiTy-1038】 Copyright (c) SinGuLaRiTy 2017. All Rights Reserved.

    Arithmetic of Bomb

    Problem Description

    众所周知,度度熊非常喜欢数字。

    它最近在学习小学算术,第一次发现这个世界上居然存在两位数,三位数……甚至N位数!

    但是这回的算术题可并不简单,由于含有表示bomb的#号,度度熊称之为 Arithmetic of Bomb。

    Bomb Number中的bomb,也就是#号,会展开一些数字,这会导致最终展开的数字超出了度度熊所能理解的范畴。比如”(1)#(3)”表示”1”出现了3次,将会被展开为”111”,

    同理,”(12)#(2)4(2)#(3)”将会被展开为”12124222”。

    为了方便理解,下面给出了Bomb Number的BNF表示。

    ```

    <bomb number> := <bomb term> | <bomb number> <bomb term>

    <bomb term> := <number> | '(' <number> ')' '#' '(' <non-zero-digit> ')'

    <number> := <digit> | <digit> <number>

    <digit> := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

    <non-zero-digit> := '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

    ```

    请将Bomb Number中所有的#号展开,由于数字可能很长,结果对 1 000 000 007 取模。

    Input

    第一行为T,表示输入数据组数。

    每组数据包含一个Bomb Expression。

    - 1≤T≤100

    - 1≤length(Bomb Number)≤1000

    Output

    对每组数据输出表达式的结果,结果对 1 000 000 007 取模。

    Sample Input

    4

    1

    (1)#(3)

    (12)#(2)4(2)#(3)

    (12)#(5)

    Sample Output

    1

    111

    12124222

    212121205

    Code

    模拟,签到题不解释。

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<cmath>
    #include<algorithm>
    
    #define ll long long
    #define inf 0x3f3f3f3f
    #define maxn 101000
    #define MOD 1000000007
    
    using namespace std;
    
    int read()
    {
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    
    int n;
    char s[maxn],ans[maxn],nows[maxn];
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%s",s+1);
            int n=strlen(s+1);
            int nowstep=0,len=0,tot=0;
            for(int i=1;i<=n;i++)if(isdigit(s[i]))
            {
                if(nowstep==1){nows[++len]=s[i];}
                else 
                    if(nowstep==2)
                    {
                        for(int j=1;j<=s[i]-'0';j++)
                            for(int k=1;k<=len;k++)
                                ans[++tot]=nows[k];
                        len=0;nowstep=0;
                    }
                    else
                        if(nowstep==0)ans[++tot]=s[i];
            }
            else
            {
                if(nowstep==0&&s[i]=='(')
                    nowstep=1;
                else if(nowstep==1&&s[i]==')')
                    nowstep=2;
            }
            long long ansnum=0;
            for(int i=1;i<=tot;i++)
                ansnum=(ansnum*10+ans[i]-'0')%MOD;
            printf("%lld
    ",ansnum);
        }
        return 0;
    }

    Arithmetic of Bomb II

    Problem Descroption

    众所周知,度度熊非常喜欢数字。
    它最近在学习小学算术,沉迷于计算A+B中不能自拔。
    但是这回的算术题可并不简单,由于含有表示bomb的#号,度度熊称之为 Arithmetic of Bomb。

    Arithmetic of Bomb的目的与普通算术一样,就是计算一些Bomb Expression的结果。比如,”1-2+3”的结果为2。然而,bomb,也就是#号,会展开一些普通表达式,这会导致需要计算的式子超出了度度熊所能理解的范畴。比如”(1-2+3)#(3)”表示”1-2+3”出现了3次,将会被展开为”1-2+31-2+31-2+3”。
    为了方便理解,下面给出了Bomb Expression的BNF表示。
    ```
    <bomb expression> := <bomb term> | <bomb expression> <bomb term>
    <bomb term> := <bomb statement> | '(' <bomb statement> ')' '#' '(' <number> ')'
    <bomb statement> := <bomb element> | <bomb statement> <bomb element>
    <bomb element> := <digit> | '+' | '-' | '*'
    <normal expression> := <norm term> | <normal expression> '+' <norm term> | <normal expression> '-' <norm term>
    <norm term> := <number> | <norm term> '*' <number>
    <number> := <digit> | <non-zero-digit> <number>
    <digit> := '0' | <non-zero-digit>
    <non-zero-digit> := '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
    ```
    请先将Bomb Expression中所有的#号展开,使其成为Normal Expression(题目的输入保证展开后是一个合法的Normal Expression),再来计算这个表达式的结果。

    Input

    第一行为T,表示输入数据组数。
    每组数据包含一个Bomb Expression。
    ●1≤T≤50
    ●1≤length(Bomb Statement)≤10
    ●1≤length(Number in Bomb term)≤10
    ●1≤length(Bomb Expression)≤300 000

    Output

    对每组数据输出表达式的结果,结果对 1 000 000 007 取模。

    Sample Input

    6
    1-2+3
    (1-2+3)#(3)
    (1)#(3)
    (1+)#(2)1
    (2*3+1)#(2)
    (2)#(2)1+1(2)#(2)

    Sample Output

    2
    60
    111
    3
    43
    343

    Code

    我还不会矩阵运算呀,只好先在这里放一放大牛的代码了(能做出这道题的确佩服!)

    【本题题解来自于:y5zsq

    Code

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<queue>
    using namespace std;
    typedef long long ll;
    #define maxn 300005
    #define mod 1000000007
    vector<string>term;
    vector<ll>num;
    char c[maxn]; 
    int T;
    void Deal()
    {
        term.clear(),num.clear();
        int n=strlen(c);
        for(int i=0;i<n;)
        {
            string s;
            if(c[i]=='(')
            {
                i++;
                while(c[i]!=')')s.push_back(c[i++]);
                i+=3;
                ll t=0;
                while(c[i]!=')')t=t*10+c[i++]-'0';
                if(t)term.push_back(s),num.push_back(t);
                i++;
            }
            else
            {
                while(i<n&&c[i]!='(')s.push_back(c[i++]);
                term.push_back(s),num.push_back(1);
            }
        }
    }
    typedef ll Mat[4][4];
    Mat A,B,C;
    void Mul(Mat &a,Mat b)
    {
        Mat c;
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
            {
                c[i][j]=0;
                for(int k=0;k<4;k++)
                    c[i][j]+=a[i][k]*b[k][j];
            }
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                a[i][j]=(c[i][j]%mod+mod)%mod;
    }
    void Pow(Mat &a,ll b)
    {
        if(b==1)return ;
        Mat c;
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                c[i][j]=(i==j);
        while(b)
        {
            if(b&1)Mul(c,a);
            Mul(a,a);
            b>>=1;
        }
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                a[i][j]=c[i][j];
    }
    ll Count()
    {
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                A[i][j]=(i==j);
        int sign=1;
        for(int k=0;k<term.size();k++)
        {
            string s=term[k];
            ll t=num[k];
            int n=s.size();
            for(int i=0;i<4;i++)
                for(int j=0;j<4;j++)
                    B[i][j]=(i==j);
            for(int i=0;i<n;i++)
            {
                memset(C,0,sizeof(C));
                C[0][0]=C[3][3]=1;
                if(s[i]>='0'&&s[i]<='9')
                    C[1][1]=10,C[2][1]=s[i]-'0',C[2][2]=1;
                else if(s[i]=='+')
                    C[1][0]=sign,C[3][2]=1,sign=1;
                else if(s[i]=='-')
                    C[1][0]=sign,C[3][2]=1,sign=-1;
                else C[1][2]=1;
                Mul(B,C); 
            }
            Mul(A,B);
            if(t>1)
            {
                for(int i=0;i<4;i++)
                    for(int j=0;j<4;j++)
                        B[i][j]=(i==j);
                for(int i=0;i<n;i++)
                {
                    memset(C,0,sizeof(C));
                    C[0][0]=C[3][3]=1;
                    if(s[i]>='0'&&s[i]<='9')
                        C[1][1]=10,C[2][1]=s[i]-'0',C[2][2]=1;
                    else if(s[i]=='+')
                        C[1][0]=sign,C[3][2]=1,sign=1;
                    else if(s[i]=='-')
                        C[1][0]=sign,C[3][2]=1,sign=-1;
                    else C[1][2]=1;
                    Mul(B,C); 
                }
                Pow(B,t-1);
                Mul(A,B);
            }
        }
        ll ans=(A[2][0]+A[3][0])%mod;
        if(sign==1)ans=(ans+A[2][1]+A[3][1])%mod;
        else ans=(ans-A[2][1]-A[3][1])%mod;
        ans=(ans+mod)%mod;
        return ans;
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%s",c);
            Deal();
            printf("%I64d
    ",Count()); 
        }
        return 0;
    }

    Pokémon GO

    Problem Description

    众所周知,度度熊最近沉迷于 Pokémon GO。

    今天它决定要抓住所有的精灵球!
    为了不让度度熊失望,精灵球已经被事先放置在一个2*N的格子上,每一个格子上都有一个精灵球。度度熊可以选择任意一个格子开始游戏,抓捕格子上的精灵球,然后移动到一个相邻的至少有一个公共点的格子上继续抓捕。例如,(2, 2) 的相邻格子有(1, 1), (2, 1) 和 (1, 2) 等等。
    现在度度熊希望知道将所有精灵球都抓到并且步数最少的方案数目。两个方案被认为是不同,当且仅当两个方案至少有一步所在的格子是不同的。

    Input

    第一行为T,表示输入数据组数。
    每组数据包含一个数N。
    ●1≤T≤100
    ●1≤N≤10000

    Output

    对每组数据输出方案数目,结果对 1 000 000 007 取模。

    Sample Input

    3
    1
    2
    3

    Sample Input

    2
    24
    96

    Code

    动态规划

    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    
    #define ll long long
    const int maxn=10010,MOD=1000000007;
    
    ll a[maxn],b[maxn],n;
    
    int main()
    {
        b[1]=1;
        for(int i=2;i<=maxn;i++)
            b[i]=(b[i-1]*2)%MOD;
        a[1]=1;
        a[2]=6;
        for(int i=3;i<=maxn;i++)
            a[i]=(2*a[i-1]+b[i]+4*a[i-2])%MOD;
        int T;
        scanf("%d",&T);
        while(T--)
        {
            int n;
            scanf("%d",&n);
            ll ans=0;
            for(int i=2;i<=n-1;i++)
                ans=(ans+16*b[i-1]%MOD*a[n-i])%MOD;
            ans=(ans+4*a[n])%MOD;
            if(n==1)
                ans=2;
            printf("%lld
    ",ans);
        }
        return 0;
    }

    Pokémon GO II

    Problem Description

    众所周知,度度熊最近沉迷于 Pokémon GO。

    由于太过沉迷,现在它只能按照游戏内置的指令行走了:对,简直就像一个现实中的Pokémon!
    游戏内置的指令实际上可以抽象成一种:保持现在的朝向前行X米,然后右转。度度熊相信,只要遵循这个指令,它就一定可以抓到最珍奇的精灵球。
    但不幸的是,这个指令并不是很有可信度,有时会引导度度熊走回原来的位置。现在它想知道,在第几条指令时它第一次回到已经走过的位置?如果这种情况没有发生,请输出 “Catch you”。

    Input

    第一行为T,表示输入数据组数。
    每组数据的第一行包含一个数N,表示指令长度。接着的一行包含N个数字Xi,表示第i个指令中前行的距离。
    ● 1≤T≤100
    ● 1≤N≤1 000 000
    ● 1≤Xi≤1 000 000 000

    Output

    对每组数据输出第一次回到已经走过的位置时的指令下标i (1≤i≤N)。
    如果这种情况没有发生,请输出 “Catch you”。

    Sample Input

    3
    4
    2 2 2 2
    4
    2 1 3 1
    5
    2 1 3 1 3

    Sample Output

    4
    Catch you
    5

    Code

    目测几何神犇题,发现可以画画图找规律......第一次覆盖一定发生在轨迹的前8段中。

    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<cstdlib>
    
    #define MAXN 1000010
    
    using namespace std;
    
    const int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
    int N,a[MAXN];
    
    struct Point
    {
        int x,y;
        Point(int _x=0,int _y=0):x(_x),y(_y){}
    }points[MAXN];
    
    bool overlap(int a,int b,int c,int d)
    {
        if(a>b)
            swap(a, b);
        if(c>d)
            swap(c, d);
        return !(b<c||d<a);
    }
    
    bool intersect(Point a1,Point a2,Point b1,Point b2)
    {
        bool is_vertical_a=(a1.x==a2.x),is_vertical_b=(b1.x==b2.x);
        if(is_vertical_a && is_vertical_b)
            return a1.x==b1.x&&overlap(a1.y,a2.y,b1.y,b2.y);
        if(!is_vertical_a && !is_vertical_b)
            return a1.y==b1.y&&overlap(a1.x,a2.x,b1.x,b2.x);
        if(is_vertical_a)
        {
            swap(a1,b1);
            swap(a2,b2);
        }
        return !(max(a1.x,a2.x)<b1.x||min(a1.x,a2.x)>b1.x||max(b1.y,b2.y)<a1.y||min(b1.y,b2.y)>a1.y);
    }
    
    int solve()
    {
        int x=0,y=0;
        for(int i=0;i<N;++i)
        {
            x+=dx[i&3]*a[i];
            y+=dy[i&3]*a[i];
            points[i+1].x=x;
            points[i+1].y=y;
            for(int j=max(0,i-8);j<i-2;++j)
                if(intersect(points[j],points[j+1],points[i],points[i+1]))
                    return i;
        }
        return -1;
    }
    
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            scanf("%d",&N);
            for(int i=0;i<N;++i)
                scanf("%d",a+i);
            int result=solve();
            if(result==-1)
                printf("Catch you
    ");
            else
                printf("%d
    ", result+1);
        }
        return 0;
    }

    Valley Numer

    Problem Description

    众所周知,度度熊非常喜欢数字。
    它最近发明了一种新的数字:Valley Number,像山谷一样的数字。

    当一个数字,从左到右依次看过去数字没有出现先递增接着递减的“山峰”现象,就被称作 Valley Number。它可以递增,也可以递减,还可以先递减再递增。在递增或递减的过程中可以出现相等的情况。
    比如,1,10,12,212,32122都是 Valley Number。
    121,12331,21212则不是。
    度度熊想知道不大于N的Valley Number数有多少。
    注意,前导0是不合法的。

    Input

    第一行为T,表示输入数据组数。
    每组数据包含一个数N。
    ● 1≤T≤200
    ● 1≤length(N)≤100

    Output

    对每组数据输出不大于N的Valley Number个数,结果对 1 000 000 007 取模。

    Sample Input

    3
    3
    14
    120

    Sample Input

    3
    14
    119

    Code

    记忆化搜索/数位DP

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cctype>
    #define ll long long
    using namespace std;
    const ll maxn=110,MOD=1000000007;
    ll f[maxn][2][10],a[maxn],n;
    char s[maxn];
    
    ll dfs(ll pos,ll state,ll limit,ll pre)
    {
        if(pos==-1)
        {
            if(~pre)
                return 1;
            else
                return 0;
        }
        if(!limit&&~pre&&~f[pos][state][pre])
            return f[pos][state][pre];
        ll up=limit?a[pos]:9;
        ll ans=0;
        for(int i=0;i<=up;i++)
        {
            if(pre==-1&&i==0)
                ans=(ans+dfs(pos-1,state,limit&&i==up,pre))%MOD;
            else if(pre==-1&&i!=0)
                ans=(ans+dfs(pos-1,state,limit&&i==up,i))%MOD;
            else if(state==0)
                ans=(ans+dfs(pos-1,i>pre,limit&&i==up,i))%MOD;
            else if(state==1&&i>=pre)
                ans=(ans+dfs(pos-1,state,limit&&i==up,i))%MOD;
        }
        if(!limit&&~pre)
            f[pos][state][pre]=ans;
        return ans;
    }
    
    int main()
    {
        ll T;
        scanf("%lld",&T);
        memset(f,-1,sizeof(f));
        while(T--)
        {
            scanf("%s",s+1);
            n=strlen(s+1);
            for(int i=1;i<=n;i++)
                a[n-i]=s[i]-'0';
            printf("%lld
    ",dfs(n-1,0,1,-1));
        }
        return 0;
    }

    Valley Numer II

    Problem Description

    众所周知,度度熊非常喜欢图。
    它最近发现了图中也是可以出现 valley —— 山谷的,像下面这张图。

    为了形成山谷,首先要将一个图的顶点标记为高点或者低点。标记完成后如果一个顶点三元组<X, Y, Z>中,X和Y之间有边,Y与Z之间也有边,同时X和Z是高点,Y是低点,那么它们就构成一个valley。
    度度熊想知道一个无向图中最多可以构成多少个valley,一个顶点最多只能出现在一个valley中。

    Input

    第一行为T,表示输入数据组数。
    每组数据的第一行包含三个整数N,M,K,分别表示顶点个数,边的个数,标记为高点的顶点个数。
    接着的M行,每行包含两个两个整数Xi,Yi,表示一条无向边。
    最后一行包含K个整数Vi,表示这些点被标记为高点,其他点则都为低点。
    ● 1≤T≤20
    ● 1≤N≤30
    ● 1≤M≤N*(N-1)/2
    ● 0≤K≤min(N,15)
    ● 1≤Xi, Yi≤N, Xi!=Yi
    ● 1≤Vi≤N

    Output

    对每组数据输出最多能构成的valley数目。

    Sample Input

    3
    3 2 2
    1 2
    1 3
    2 3
    3 2 2
    1 2
    1 3
    1 2
    7 6 5
    1 2
    1 3
    1 4
    2 3
    2 6
    2 7
    3 4 5 6 7
    View Sample Input

    Sample Output

    1
    0
    2

    Code

    状压DP

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<cmath>
    #include<algorithm>
    
    #define ll long long
    
    using namespace std;
    
    int read()
    {
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    
    const int inf=0x3f3f3f3f,maxn=40,maxk=80010;
    
    int n,f[2][maxk],c,k,m,hi[maxn];
    bool Map[maxn][maxn],high[maxn];
    
    void dfs(int dep,int now,int pre,int cyc,int x)
    {
        if(dep==3)
            f[now][c]=max(f[now][c],f[pre][cyc]+1);
        else
            for(int i=0;i<=k-1;i++)
                if(Map[x][hi[i+1]]&&!(c&(1<<i)))
                {
                    c|=(1<<i);
                    dfs(dep+1,now,pre,cyc,x);
                    c^=(1<<i);
                }
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            n=read();m=read();k=read();
            int u,v;
            memset(Map,0,sizeof(Map));
            for(int i=1;i<=m;i++)
            {
                u=read();v=read();
                Map[u][v]=Map[v][u]=1;
            }
            memset(high,0,sizeof(high));
            for(int i=1;i<=k;i++)
            {
                u=read();
                high[u]=1;
            }
            int nowk=0;
            for(int i=1;i<=n;i++)if(high[i])hi[++nowk]=i;
            k=nowk;
            memset(f,0,sizeof(f));
            int x=1;
            for(int i=1;i<=n;i++)if(!high[i])
            {
                x=1-x;
                memset(f[x],0,sizeof(f[x]));
                for(int j=0;j<(1<<k);j++)
                {
                    f[x][j]=max(f[x][j],f[1-x][j]);
                    c=j;
                    dfs(1,x,1-x,j,i);
                }
            }
            int ans=0;
            for(int i=0;i<(1<<k);i++)ans=max(ans,f[x][i]);
            printf("%d
    ",ans);
        }
        return 0;
    }

    Time: 2017-08-24

  • 相关阅读:
    利用git上传到码云
    js 数组的方法总结
    什么是浏览器的回流和重绘以及如何减少回流和重绘
    数组的方法some和includes
    node.js中使用http-proxy-middleware请求转发给其它服务器
    什么是BFC
    如何用Github上传项目中的代码
    前端渲染与后端渲染的区别有哪些
    移动端路由的切换
    面试题
  • 原文地址:https://www.cnblogs.com/SinGuLaRiTy2001/p/7423138.html
Copyright © 2011-2022 走看看