zoukankan      html  css  js  c++  java
  • 2019 10.3模拟

    1. 蒜头君的兔子

    (rabbit.cpp/.in/.out 2s,256m)
    蒜头君的小伙伴在 第一年 送给他一对 一岁 的兔子,并告诉他:这种兔子 刚生下来时算 0
    ,到了 2 岁时就可以繁殖了,它在 2-10 岁时,每年会生下来一对兔子,这些兔子到了 2 岁也可
    以繁殖,但这些兔子在 10 岁那年 生完仔后 不久就会死亡,蒜头君想知道,第 n 年兔
    子 产仔之后(第 n 10 岁的兔子此时已经死亡),他会有多少对兔子。结果对
    1000000007 取模。
    输入格式
    共一行,一个正整数 n,表示蒜头君想知道第 n 年的兔子总对。
    输出格式
    输出一个整数,表示第 n 年兔子总对数对 1000000007 取模的值。
    数据规模
    对于 30% 的数据,满足 1≤n≤103
    对于 60% 的数据,满足 1≤n≤105
    对于 100% 的数据,满足 1≤n≤109
    样例输入1

    10
    样例输出1

    88
    样例输入2

    88
    样例输出2

    352138150
    样例输入3

    10086
    样例输出3
    405567313

    考点:递推 矩阵乘法
    设 f[i][j]表示第 i 年,年龄为 j 的兔子的对数。
    f[i][0]=f[i-1][1]+f[i-1][2]+...+f[i-1][9]
    f[i][1]=f[i-1][0]
    f[i][2]=f[i-1][1]
    f[i][3]=f[i-1][2]
    ......
    f[i][9]=f[i-1][8]
    f[i][10]=f[i-1][9] //已经死掉
    构造初始矩阵
    { f[i][0],f[i][1],f[i][2],...,f[i][9] }*矩阵 A={ f[i+1][0],f[i+1][1],f[i+1][2],f[i+1][3],...,f[i+1][9]}
    矩阵 A
    0 1 0 0 0 0 0 0 0 0
    1 0 1 0 0 0 0 0 0 0
    1 0 0 1 0 0 0 0 0 0
    1 0 0 0 1 0 0 0 0 0
    1 0 0 0 0 1 0 0 0 0
    1 0 0 0 0 0 1 0 0 0
    1 0 0 0 0 0 0 1 0 0
    1 0 0 0 0 0 0 0 1 0
    1 0 0 0 0 0 0 0 0 1
    1 0 0 0 0 0 0 0 0 0
    矩阵乘法即可
    (感谢黄学长讲解)

    #include<bits/stdc++.h>
    using namespace std;long long f[12][12],c[12][12];
    void cheng(long long a[12][12],long long b[12][12])//矩阵y乘x,结果存在y中
    {
        memset(c,0,sizeof(c));
        for(int i=1;i<=10;i++)
        for(int k=1;k<=10;k++)
        for(int j=1;j<=10;j++)
        c[i][j]=(c[i][j]+(a[i][k]*b[k][j])%1000000007)%1000000007;
        memcpy(a,c,sizeof(c));
    }
    long long ans[12][12];
    void prepare(int b)//二分快速幂求A^(n-1)
    {
        for(int i=1;i<=10;i++)ans[i][i]=1;
        while(b)
        {
            if(b&1)cheng(ans,f);
            b>>=1;
            cheng(f,f);
        }
    }
    int main()
    {
        int n;
        cin>>n;
        for(int i=2;i<=10;i++)f[i][1]=1;
        for(int i=2;i<=10;i++)f[i-1][i]=1;
        prepare(n-1);
        int sum=0;
        for(int i=1;i<=10;i++)sum=(sum+ans[2][i])%1000000007;//一开始只有一对一岁的兔子
        cout<<sum%1000000007;
    }


    2. 蒜头君的排序

    (sort.cpp/.in/.out 2s,256m)
    蒜头君是一个爱思考的好孩子,这一天他学习了冒泡排序,于是他就想,把一个乱序排列通过
    冒泡排序排至升序需要多少次交换,这当然难不倒他,于是他想来点刺激的,给定一个 1…
    n 的排列,每次从该排列中选择一个区间 [l,r],问使用冒泡排序将该区间排至升序需要多少次交换
    操作。
    输入格式
    第一行一个整数 n,表示排列长度。
    接下来一行 n 个整数,表示该排列。
    接下来一行一个整数 m,表示询问次数。
    接下来 m 行,每行 2 个整数 l,r,表示询问 [l,r] 区间。
    输出格式
    输出 m 行,每行 1 个整数,第 i 行表示第 i 个询问的答案。
    数据规模
    对于 30% 的数据,满足 1 ≤ n,m ≤ 300
    对于 60% 的数据,满足 1 ≤ n,m ≤ 1000
    对于 100% 的数据, 满足 1 ≤ n,m ≤ 30000, l < r, ∣l[i] - l[i - 1]∣ + ∣r[i]- r[i - 1]∣ ≤ 7 × 106
    样例输入

    10
    9 8 7 4 5 6 10 3 2 1
    5 2
    4
    8 10
    2 8
    5 9
    4 9
    样例输出
    3

    3

    13

    7

    9

    考点:逆序对 莫队思想
    如果已经求出区间 [l,r]的逆序对数,那么我们可以用类似莫队的思想快速求出 [l-
    1,r],[l+1,r],[l,r+1],[l,r-1]的逆序对
    如果知道区间[l , r]中的逆序对个数,那么也可以快速求出区间[l-1 , r], [l+1 , r], [l , r-1], [l ,
    r+1]的逆序对个数。
    ③ [l-1 , r]的个数 = [l , r]的个数 + [l , r]中比 a[l-1]小的元素的个数
    ① [l+1 , r]的个数 = [l , r]的个数 - [l+1 , r]中比 a[l]小的元素的个数
    ② [l , r-1]的个数 = [l , r]的个数 - [l , r-1]中比 a[r]大的元素的个数
    ① [l , r+1]的个数 = [l , r]的个数 + [l , r]中比 a[r+1]大的元素的个数
    Lt,Rt 表示处理完当前询问后,讨论指针所指向的区间边界。
    那么对于新的一个询问[x,y]
    1.Rt<y
    while(Rt<y)
    Rt++;
    ans+=getSum(n)-getSum(A[Rt]-1)//统计之前出现过的,比 A[Rt]要大的数字的个数,即
    A[Rt]贡献的逆序对数。
    modify(Rt,1) //将 A[Rt]加入树状数组


    2.Rt>y
    while(Rt>y)
    modify(A[Rt],-1) //在添加 A[Rt]进入树状数组之前, [Rt,n]之间的数都与
    A[Rt]构成逆序对
    ans-=getSum(n)-getSum(A[Rt]-1)//将 A[Rt]贡献的逆序对从答案中减掉
    Rt--


    3.Lt<x
    while(Lt<x)
    modify(A[Lt],-1) //在添加 A[Lt]进入树状数组前, [1,Lt]区间的数字都比 A[Lt]
    要小,它们都与后加入的 A[Lt]构成逆序对。
    ans-=getSum(A[Lt]-1)
    Lt++

    4.Lt>x

    while(Lt>x) Lt-- //在区间[1,Lt-1]的数字,都与 A[Lt]构成逆序对。即之前出现过的比 A[Lt]小的数字

    ans+=getSum(A[Lt]-1)
    modify(A[Lt],1)


    3. 蒜头君救人

    (rescue.cpp/.in/.out 2s,512m)
    蒜头君是一个乐于助人的好孩子,这天他所在的乡村发生了洪水,有多名村民被困于孤岛
    上,于是蒜头君决定去背他们离开困境,假设蒜头君所在的村子是 n × m 的网格,网格中.
    号代表平地, #号代表该地已被洪水淹没, AB ……等大写字母表示该地有村民被困, s 代表
    蒜头君的起点, t 代表蒜头君的终点。
    蒜头君的初始速度为 k 秒一格,他每次可以向上下左右 4 个方向中的一个移动 1 格。在背上
    一个村民后,他的速度可能会降低,也可能会加快,但他的速度不能快于 1 秒每格,那么蒜头君
    想知道,他最快需要多长时间将所有村民救出?
    注意:不能在终点以外的地方放下村民;可以同时背多个村民。


    输入格式
    第一行 3 个正整数 n,m,k,分别表示村庄长度、宽度、蒜头君初始速度。
    接下来 n 行,每行一个长度为 m 的字符串,表示村庄的地形,字符串意义如上所述。
    接下来若干行,每行一个大写字母、一个整数,表示该编号的村民会使 k 增加 / 减少多少。行数等
    同于地形中大写字母的个数。大写字母按字典序,即 ABC 的顺序排列,保证前后两行的字母是
    连续的。


    输出格式
    输出 1 个整数,表示最小用时。


    数据规模
    对于 10% 的数据,满足 1 ≤ n,m ≤ 5,村民个数为 1
    对于 50% 的数据,满足 1 ≤ n,m ≤ 5,村民个数小于等于 5
    对于 100% 的数据,满足 1 ≤ n,m ≤ 10,村民个数小于等于 10
    样例输入

    4 4 2
    s.##
    ..A#
    .B##
    ...t
    A -3
    B 4

    样例输出
    17

    考点:状压 DP floyd
    状态 f[S1][S2][p]表示背着的村民集合 S1,已到终点的村民集合 S2,蒜头君处在 p 位置(p 只
    取初始状态下村民的位置、终点位置),那么显然有状态转移:
    接村民:f[s1|(1<<y-1)][S2][y] = min{ dis(x,y)*v[s1]+f[s1][s2][x]}
    (x∉S2,x∈S1,y∉S2,y∉S1)
    终点处放下村民:f[s1^T][S2|T][end]=min(f[S1^T][S2|T][end],f[S1][S2][end])
    (T 为子集,T∈S1,end 为终点)
    因为在这样的定义下,S1 与 S2 是不能有交集的,这样显然不可能的情况在循环里判断一下
    就可以了,实际上可能合法的情况只有 3^cnt 种。
    再加上 x,y 与两个集合间的关系,循环执行的次数不会特别多

  • 相关阅读:
    如何使用Eclipse和GCC搭建STM32环境
    增量式pid和位置式PID参数整定过程对比
    webrtc 源码结构
    小米路由器刷Xiaomi Mi WiFi Mini openwrt
    js jQuery 右键菜单 清屏
    沉默的大多数 (王小波)
    kindle书摘-活着-余华-活着不易,珍惜
    kindle书摘-围城-相爱勿相伤
    Nagios系列1,选择
    红楼梦人物关系图,一代大师成绝响,下回分解待何人,kindle读书摘要
  • 原文地址:https://www.cnblogs.com/CXYscxy/p/11620016.html
Copyright © 2011-2022 走看看