zoukankan      html  css  js  c++  java
  • 8.9模拟赛观光记

    这次模拟赛来得猝不及防,以至于我还没来得急膜yyb(rp--)

    T1

    游戏

    Description

    Bob经常与Alice一起玩游戏。今天,他们在一棵树上玩游戏。Alice有M1块石子,Bob有M2块石子,游戏一开始,所有石头放在树的节点处,除了树根。Alice先移然后两人轮流移动,每次移动只能选择自己的一个石子,而且只能从当前位置移到父亲节点处,游戏过程中允许一个节点处放多个石子。
      谁先把自己所有的石子移到树根处谁就失败了,假设两人都是非常聪明,游戏过程中都使用最优策略,给定石子起始位置,要你计算出谁是赢家。

    Input

     

    输入包含多组测试数据。
      第一行输入T(T<=10)表示测试数据组数。
      接下来每组测试数据第一行输入3个整数N(1<=N<=10000),M1(1<=M1<=10000),M2(1<=M2<=10000),其中N表示树的节点数。
      接下来N-1行描述树,每行包含两个整数A和B(0<=A,B<=N-1)表示树中有一条边连接A,B两点,注意0是树根。
      接下来一行M1个数,表示Alice的M1个石子的位置。
      接下来一行M2个数,表示Bob的M2个石子的位置。

     

    Output

      对于每组测试数据,输出赢家的名字。

    Sample Input

    
    

    2
    3 1 1
    0 1
    2 0
    1
    2
    3 2 1
    0 1
    1 2
    2 2
    2

     

    Sample Output

    Bob
    Alice

    Hint

    【数据说明】
    对于30%的数据,满足1<=N<=10,1<=M1,M2<=3
    对于100%的数据,满足1<=N<=10000,1<=M1,M2<=10000

    上来打开T1一看,天哪考博弈论,后来瞪了半天才发现每次移动只能选一个石子而且只能向上跳一次,把两个人的dep总和比一比就好了,如果相同,则输出先手(Alice)

    #include<iostream>
    #include<iomanip>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define int long long
    inline int read() {
        char ch;
        bool bj=0;
        while(!isdigit(ch=getchar()))
            bj|=(ch=='-');
        int res=ch^(3<<4);
        while(isdigit(ch=getchar()))
            res=(res<<1)+(res<<3)+(ch^(3<<4));
        return bj?-res:res;
    }
    void printnum(int x) {
        if(x>9)printnum(x/10);
        putchar(x%10+'0');
    }
    inline void print(int x,char ch) {
        if(x<0) {
            putchar('-');
            x=-x;
        }
        printnum(x);
        putchar(ch);
    }
    int m1,m2,n,h[100005],cnt,dep[100005];
    struct Edge {
        int to,nxt;
    } w[100005<<1];
    inline void AddEdge(int x,int y) {
        w[++cnt].to=y;
        w[cnt].nxt=h[x];
        h[x]=cnt;
    }
    void DFS(int x,int fa,int depth) {
        dep[x]=depth;
        for(int i=h[x]; i; i=w[i].nxt) {
            int v=w[i].to;
            if(v==fa)continue;
            DFS(v,x,depth+1);
        }
    }
    signed main() {
        int T=read();
        while(T--) {
            memset(h,0,sizeof(h));
            cnt=0;
            memset(w,0,sizeof(w));
            memset(dep,0,sizeof(dep));
            n=read();
            m1=read();
            m2=read();
            int x,y;
            for(int i=1; i<n; i++) {
                x=read()+1;
                y=read()+1;
                AddEdge(x,y);
                AddEdge(y,x);
            }
            DFS(1,0,0);
            int cnt1=0,cnt2=0;
            for(int i=1; i<=m1; i++) {
                x=read()+1;
                cnt1+=dep[x];
            }
            for(int i=1; i<=m2; i++) {
                x=read()+1;
                cnt2+=dep[x];
            }
            if(cnt1>cnt2)puts("Alice");
            else if(cnt1<cnt2)puts("Bob");
            else puts("Bob");
        }
        return 0;
    }

    期望得分:100

    实际得分:100

    T1打完后很虚,毕竟我也不知道结论对不对。然后把2、3、4题都看了一遍,没有任何头绪,只好老老实实地打T2

    T2

     

    阅读程序写结果

    Description

     NOIP2009普及组初赛阅读程序第三题如下:
      #include
      using namespace std;
      const int c=2009; 
      int n,p,s,i,j,t; 
      int main()
      { cin>>n>>p; 
        s=0; 
        t=1; 
       for(i=1;i<=n;i++) 
       { t=t*p%c; 
        for(j=1;j<=i;j++)s=(s+t)%c; 
       }
       cout << s << endl;
       return 0; 
      }
      输入:11 2
      输出:______
      这题很简单,死做都能做出来,但如果扩大N的范围,你还能做吗?

    Input

     输入N(1<=N<=10^1000),P(1<=P<=1000),之间用一个空格隔开。

    Output

      输出结果。

    Sample Input

    11 2

    Sample Output

    782

    Hint

    【数据规模】
      对于50%的数据,N<=1,000,000
      对于100%的数据,N<=10^1000

    看到这道题我就想起了"丢失的题面",仔细读题后才松了口气,代码都给你了,这种题的套路就是打表找规律, 然后我打出了10×10的表。

     

    1 2 3 4 5 6 7 8 9 10
    3 10 21 36 55 78 105 136 171 210
    6 34 102 228 430 726 1134 1672 349 1201
    10 98 426 1252 921 1892 693 1984 476 1021
    15 258 1641 345 474 592 350 1086 398 780
    21 642 1997 813 1810 1277 1085 903 761 1906
    28 1538 1234 988 228 45 56 1204 1559 310
    36 1577 1488 927 1233 781 1869 1660 583 438
    45 158 1843 1657 608 1731 1330 1746 746 1878
    55 353 1687 437 1377 698 1379 55 367 1806

    并没有什么规律,突然发现它取了模数,去掉之后再来一次。

    1 2 3 4 5 6 7 8 9 10
    3 10 21 36 55 78 105 136 171 210
    6 34 102 228 430 726 1134 1672 2358 3210
    10 98 426 1252 2930 5910 10738 18056 28602 43210
    15 258 1641 6372 18555 44790 94773 181896 323847 543210
    21 642 6015 30948 112305 324726 800667 1754760 3512493 6543210
    28 1538 21324 145636 659180 2284278 6565468 16434824 36993276 76543210
    36 3586 73812 669924 3784180 15721206 52683876 150652552 381367044 876543210
    45 8194 250959 3029220 21362305 106420470 415866339 1358612104 3868151445 9876543210
    55 18434 841449 13514980 119018555 711082230 3240618829 12096030344 38735995455 109876543210

    emm...如果我TMD看得出来规律就去数竞了

    还是只能回归代码,突然发现

    for(j=1;j<=i;j++)s=(s+t)%c; 

    不就是

    s=(s+t*i)%c

    吗?

    t=t*p%c; 

    不就是

    pow(p,i)%c

    吗?

    然后就可以打出公式,设f[i]为(i,p)的答案,所以

    f[i]=f[i-1]+pow(p,i)×i%c  就是  f[i]=∑i=1npow(p,i)×i%c。

    50pts到手

    回头看了一眼数据范围  N<=10^1000,疯狂暗示O(logn)做法呀,然后顺手推了个矩阵快速幂

     

    推完式子以后心中一凉,我矩阵快速幂忘了,与是花了30min+把矩阵快速幂调了出来。

    随手拍了几百组数据,感觉十分嚣张(要完的前奏),直接来一组极限数据,结果爆零了。脑袋突然开窍:N<=10^1000,这TM要写高精度啊!但30min+写出来的东西不能白白浪费,于是咬咬牙,撸了个高精出来,又是30min+,然后继续挂机对拍的同时开T3。

     

    #include<iostream>
    #include<iomanip>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define int long long
    inline int read() {
        char ch;
        bool bj=0;
        while(!isdigit(ch=getchar()))
            bj|=(ch=='-');
        int res=ch^(3<<4);
        while(isdigit(ch=getchar()))
            res=(res<<1)+(res<<3)+(ch^(3<<4));
        return bj?-res:res;
    }
    void printnum(int x) {
        if(x>9)printnum(x/10);
        putchar(x%10+'0');
    }
    inline void print(int x,char ch) {
        if(x<0) {
            putchar('-');
            x=-x;
        }
        printnum(x);
        putchar(ch);
    }
    const int Mod=2009;
    int f[5],a[5][5],p;
    inline void mul(int f[],int a[][5]) {
        int c[5]= {0};
        for(int i=1; i<=3; i++)
            for(int j=1; j<=3; j++)
                c[i]=(c[i]+a[j][i]*f[j]%Mod)%Mod;
        memcpy(f,c,sizeof(c));
    }
    inline void mulself(int a[][5]) {
        int c[5][5]= {0};
        for(int i=1; i<=3; i++)
            for(int j=1; j<=3; j++)
                for(int k=1; k<=3; k++)
                    c[i][j]=(c[i][j]+a[k][j]*a[i][k]%Mod)%Mod;
        memcpy(a,c,sizeof(c));
    }
    struct node {
        int num[1005];
        inline void set() {
            memset(num,0,sizeof(num));
        }
        inline void read() {
            char s[1005];
            scanf("%s",s);
            if(s[0]=='0') {
                num[0]=0;
                return;
            }
            num[0]=strlen(s);
            for(int i=num[0]; i; i--)num[i]=s[num[0]-i]-'0';
        }
        inline void print() {
            if(!num[0]) {
                puts("0");
                return;
            }
            for(int i=num[0]; i; i--)printf("%d",num[i]);
            puts("");
        }
        inline void Half() {
            for(int i=num[0]; i; i--)
                if(i!=1) {
                    num[i-1]+=(num[i]&1)?10:0;
                    num[i]/=2;
                } else num[i]/=2;
            while(!num[num[0]]&&num[0])num[0]--;
        }
    } n;
    inline void Solve(node n,int p) {
        memset(f,0,sizeof(f));
        memset(a,0,sizeof(a));
        f[1]=f[2]=p;
        a[1][1]=a[1][2]=a[2][2]=p;
        a[2][3]=a[3][3]=1;
        while(n.num[0]) {
            if(n.num[1]&1)mul(f,a);
            mulself(a);
            n.Half();
        }
        print(f[3],'
    ');
    }
    signed main() {
        n.set();
        n.read();
        p=read();
        Solve(n,p);
        return 0;
    }

     

    期望得分:100

    实际得分:100

     

    T3

    01路径

    Description

    小Z处在4个由传送门连接的奇怪的房间内。房间标记为A、B、C和D。每个房间里有两个按钮,标记为0和1。在A房间按0号按钮会被传送到C房间,反之在C号房间按0号按钮会被传送到A房间;在B房间按0号按钮会被传送到D房间,反之类似。类似的,在A房间按1号按钮会被传送到B房间,在C房间按1好按钮会被传送到D房间,反之一样。这个传送关系可以如下图来表示:
    按恰好n次按钮称之为n长度的01路径。显然,经过每个n长度的01路径后,小Z将会停留在某个房间。小Z想知道终点在R房间、字典序第K小的n长度01路径是哪一条。
      开始的时候,小Z总是在A房间。

    Input

     一行,包含一个字母R和两个数字n和K,之间用空格隔开。R是A、B、C、D中的一个。

    Output

      一行,输出终点在R房间、字典序第K小的01路径。如果无解,输出“impossible”。

    Sample Input1

    B 3 2

    Sample Output1

    010

    Sample Input2

    D 1 1

    Sample Output2

    impossible

    Hint

    【样例解释】
      第一个样例,所以可能的路径,按字典序排序,是:000,001,010,011,100,101,110,111。
      路径001 (A -> C -> A -> B), 010 (A -> C -> D -> B), 100 (A -> B -> D -> B) 和 111 (A -> B -> A -> B)是终点在B房间的路径。字典序第二个为010。
      第二个样例,从A点出发1步之内到达不了D房间。
    【数据说明】
      50%数据,1<=n<=50,1<=k<=10^18。
      100%数据,100<=n<=1000,1<=k<=10^400

    本来奔着AC去的,挤破脑袋都没想出来,看数据范围又要高精。而且好像200pts已经到手了,那么就安安心心的打爆搜吧。

    期望得分:10

    实际得分:0(居然一个impossible的点都没有!)

    赛后解析(待填坑)

    T4

    有趣的数列[HNOI2009]

    Description

    我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件:
      (1)它是从1到2n共2n个整数的一个排列{ai};
      (2)所有的奇数项满足a1 < a3 < … < a2n-1,所有的偶数项满足a2 < a4 < … < a2n;
      (3)任意相邻的两项a2i-1与a2i(1 ≤ i ≤ n)满足奇数项小于偶数项,即:a2i-1 < a2i。
      现在的任务是:对于给定的n,请求出有多少个不同的长度为2n的有趣的数列。因为最后的答案可能很大,所以只要求输出答案 mod P的值。

    Input

      从文件中读入数据,输入文件只包含用空格隔开的两个整数n和P。

    Output

      输出文件中仅含一个整数,表示不同的长度为2n的有趣的数列个数mod P的值。

    Sample Input

    3 10

    Sample Output

    5

    Hint

    【样例说明】
      对应的5个有趣的数列分别为(1,2,3,4,5,6),(1,2,3,5,4,6),(1,3,2,4,5,6),(1,3,2,5,4,6),(1,4,2,5,3,6)。
    【数据说明】
      50%的数据满足n≤1000且P<=1,000,000
      100%的数据满足n≤1,000,000且P≤1,000,000,000。

     全排列大法吼啊!飞快地打完了时间复杂度极其优秀的O(n!)算法,后来发现题目给定的条件可以在DFS过程中判定,算是剪枝吧,时间复杂度O(玄学),能在极其短的时间内跑过n<=7的数据范围。

    暴力打完了,颓颓颓

    在离交卷还有20min的时候,我想到了把T4的表打出来看看:

    1 2 5 14 42

    ???似曾相识???好像是卡特兰数?

    无奈卡特兰数的通项我又忘了,好像是Cn2n/n+1,代了几个数进去,竟然是对的!

    然后怎么办?Lucas定理?乘法逆元?不互质啊!

    拓展Lucas?想都别想,最后在还剩15min时,我终于想到了通过唯一分解上下加减约分(好丢脸啊,这种题我之前做过)。

    打完以后(幸好码量不大),再次自信地跑极限数据,跑了10秒...

    怎么办?果断撤掉试除法,换上魔改后的欧氏筛,过了极限数据。

    最后对拍了几百组,好像是对的。

     

    #include<iostream>
    #include<iomanip>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define int long long
    inline int read() {
        char ch;
        bool bj=0;
        while(!isdigit(ch=getchar()))
            bj|=(ch=='-');
        int res=ch^(3<<4);
        while(isdigit(ch=getchar()))
            res=(res<<1)+(res<<3)+(ch^(3<<4));
        return bj?-res:res;
    }
    void printnum(int x) {
        if(x>9)printnum(x/10);
        putchar(x%10+'0');
    }
    inline void print(int x,char ch) {
        if(x<0) {
            putchar('-');
            x=-x;
        }
        printnum(x);
        putchar(ch);
    }
    int p[5000005],a[5000005];
    bool vst[5000005];
    int n,P,cnt;
    int ans=1;
    inline void pre(int x) {
        for(int i=2; i<=x; i++) {
            if(vst[i])continue;
            p[++cnt]=i;
            for(int j=2; i*j<=x; j++)vst[i*j]=1;
        }
    }
    inline void Solve(int l,int r,int d) {
        for(int i=1; i<=cnt&&p[i]<=r; i++) {
            for(int j=1; p[i]*j<=r; j++)
                if(j*p[i]>=l&&j*p[i]<=r) {
                    int tmp=j*p[i];
                    while(tmp%p[i]==0) {
                        tmp/=p[i];
                        a[i]+=d;
                    }
                }
        }
    }
    inline int quick_pow(int a,int n) {
        int sum=1;
        while(n) {
            if(n&1)sum=sum*a%P;
            a=a*a%P;
            n>>=1;
        }
        return sum;
    }
    signed main() {
        n=read();
        pre(n<<1);
        P=read();
        Solve(1,n,-1);
        Solve(n+2,(n<<1),1);
        for(int i=1; i<=cnt; i++)
            ans=ans*quick_pow(p[i],a[i])%P;
        print(ans,'
    ');
        return 0;
    }

     

    期望得分:100

    实际得分:100

    得分情况:100(100)+100(100)+0(10)+100(100)=300(310)

    感觉考得一般,主要是T2有些怪异和T4做过相似的题,不是真实水平。

    300pts是rank2,好像300pts有很多人。

    隔壁的W奆奆AK了,我们一起来%他。

    stO--->https://blog.csdn.net/weixin_43821906<---Orz

    OI尚未结束,蒟蒻仍需努力

     

  • 相关阅读:
    MySql多表循环遍历更新
    GridView控件的选择功能,代码实现CheckBox控件的全选、反选以及取消
    使用HTTP POST请求12306网站接口查询火车车次API
    GridView控件的绑定分页功能
    使用HTTP GET请求12306网站接口获取车站名和车站Code
    浅谈从Oracle数据库中取出10条数据的Select语句与Sql Server、MySql的区别
    2022 程序员口语提升指南
    R语言与java整合
    新浪的股票接口 c# (收藏)
    摘记
  • 原文地址:https://www.cnblogs.com/soledadstar/p/11328795.html
Copyright © 2011-2022 走看看