• 2016 Multi-University Training Contest 3 部分题解


      1001,只要枚举区间即可。签到题,要注意的是输入0的话也是“TAT”。不过今天补题的时候却WA了好几次,觉得奇怪。原来出现在判断条件那里,x是一个int64类型的变量,在进行(x<65536*65536)的时候,后面的已经爆int了!因为如果写的是int类型他就默认是int类型的。所以要写成(ll)65536*65536或者直接4294967296,因为如果这个值是ll类型的,就自动用ll类型来保存了(另外要注意的是(ll)(65536*65536)也是错的!因为后面已经爆int了,再转成ll就没意义了)。看来写代码要小心再小心。不过我们昨天1A,也是因为一开始打表的时候已经把4294967296算出来了,不然如果让我直接敲的话,可能在这签到题上都会WA到死啊- -。。说明有时候运气也是ACM的一部分。- -!代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 
     5 char s[100+5];
     6 
     7 int main()
     8 {
     9     while(scanf("%s",s)==1)
    10     {
    11         int len = strlen(s);
    12         if(len>10) puts("TAT");
    13         else
    14         {
    15             ll x = 0;
    16             for(int i=0;s[i];i++) x = x * 10 + s[i] - '0';
    17             if(x==0) puts("TAT");
    18             else if(x<2) puts("0");
    19             else if(x>=2 && x<4) puts("1");
    20             else if(x>=4 && x<16) puts("2");
    21             else if(x>=16 && x<256) puts("3");
    22             else if(x>=256 && x<65536) puts("4");
    23             else if(x>=65536 && x<(ll)65536*65536) puts("5");
    24             else puts("TAT");
    25         }
    26     }
    27 }
    View Code

      1002,队友当时是二维dp做的,我自己当时也想了一个办法,代数式化简了半天得到了一个公式,虽然后来验证了一下好像是错的,不过可能是我自己推错了,下次有空再试试。主要是用到了2*1+3*2+4*3+...+n*(n-1)这样的形式求和,这样的式子可以拆成2*(2-1)+3*(3-1)+4*(4-1)+...+n*(n-1),然后拆开,前面是平方和公式,后面是等差数列公式,然后相减即可。顺便,平方和公式是:

        

    但是看了一下题解,他的方法简直太吊了!对于一个数字在两头的情况,以在头为例,这个数字和它后面的这个数字,选择任意两个数字的情况下,只有两种比较关系(>或者<)那么这个位置的期望就是c[i]/2,同理的,在中间的时候,任选3个数只有6种可能性(3!),而中间大的情况只有两种,因此贡献是c[i]/3(可以这么理解,三个数考虑为123,那么可能性就是错排列的种数,而中间大的可能性就是3在中间的两种情况)。那么这题就做完了,另外需要特判n=1的情况。代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 
     5 int a[1000+5];
     6 
     7 int main()
     8 {
     9     int n;
    10     while(scanf("%d",&n)==1)
    11     {
    12         for(int i=1;i<=n;i++) scanf("%d",a+i);
    13         if(n==1)
    14         {
    15             printf("%f
    ",1.0*a[1]);
    16         }
    17         else
    18         {
    19             double ans = 0;
    20             for(int i=1;i<=n;i++)
    21             {
    22                 if(i==1 || i==n) ans += a[i]/2.0;
    23                 else ans += a[i]/3.0;
    24             }
    25             printf("%f
    ",ans);
    26         }
    27     }
    28 }
    View Code

      1003,博弈论。因为上一场的关系,去学了博弈论,结果这场就来这题,真是太巧了!直接1A了233(其实也是含有点运气成分的)。王和车的话,直接画出NP图即可找出规律。而皇后的话,有点像威佐夫博弈,先画出NP图,但是P点没有什么规律可寻,因此我们需要把P的坐标一个一个的写出来找规律,写出来以后豁然开朗!因为我们可以发现的是,这些坐标点都满足一个威佐夫博弈的奇异态的变化规律:每个数字都只出现一次,而且,每个坐标两点的差值是一个等差数列。这样就很好处理了!但是这不是威佐夫博弈的奇异态,不满足a[k]=[k*(sqrt(5.0)+1)/2],但是我们可以换一个方法,既然每个点都只出现一次,就可以近似O(n)的把这些点都放到一个set里面来判断这个数字是否使用过,每次都找出最小的一个没被使用过的数字,把它以及它的另一个同伴丢到另外一个装pair的set里面,这个set里面装的都是奇异态(也就是必败态),那么只要这么预处理以后,判断坐标是不是在这个set里面即可(至于如何找这个数的同伴,可以仔细考虑一下上面加粗红字的意义,也可以见代码仔细看看)。皇后的NP图如下:

    然后我们来讲一下马的规律,因为马比较特殊,它的走法可能导致平局,因此我们还得找出平局点(这里还有个要注意的地方,如果我下一步可以走向必败或者走向平局,那么我的最优策略应当是走向平局)。马的NP图如下(!是平局点):

    代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 100 + 5;
     4 typedef long long ll;
     5 typedef pair<int,int> pii;
     6 
     7 set<int> S;
     8 set<pii> S2;
     9 void init()
    10 {
    11     int now = 2;
    12     int diff = 1;
    13     S2.insert(pii(1,1));
    14     S.insert(1);
    15     for(;;)
    16     {
    17         int sz = S.size();
    18         if(sz>1000) break;
    19         if(S.find(now) == S.end())
    20         {
    21             int a = now;
    22             int b = now + diff;
    23             S2.insert(pii(a,b));
    24             S.insert(a);
    25             S.insert(b);
    26             //printf("insert !! %d %d !!
    ",a,b);
    27             now ++;
    28             diff ++;
    29         }
    30         else now ++;
    31     }
    32 }
    33 
    34 int main()
    35 {
    36     init();
    37     /*int cnt = 0;
    38     for(set<pii>::iterator it=S2.begin();;it++)
    39     {
    40         cnt ++;
    41         if(cnt > 10 ) break;
    42         printf("%d %d
    ",(*it).first,(*it).second);
    43     }*/
    44     int T;
    45     scanf("%d",&T);
    46     while(T--)
    47     {
    48         int op ,n,m;
    49         scanf("%d%d%d",&op,&n,&m);
    50         if(op==1)
    51         {
    52             if(n%2 && m %2) puts("G");
    53             else puts("B");
    54         }
    55         else if(op==2)
    56         {
    57             if(n==m) puts("G");
    58             else puts("B");
    59         }
    60         else if(op==4)
    61         {
    62             if(n>m) swap(n,m);
    63             if(S2.find(pii(n,m))==S2.end())
    64             {
    65                 puts("B");
    66             }
    67             else puts("G");
    68         }
    69         else
    70         {
    71             if(n==m && n%3==1)
    72             {
    73                 puts("G");
    74             }
    75             else
    76             {
    77                 if(n>m) swap(n,m);
    78                 if(m%3==0 && m-n==1) puts("B");
    79                 else puts("D");
    80             }
    81         }
    82     }
    83 
    84 }
    View Code

    ——————————————————————伟大的博弈论的分界线——————————————————————————————

      偶然间看到别人这题的博客,关于皇后的方法,似乎就是完完全全的威佐夫博弈。= =!原型的话,令k=两数之差,那么有a[k]=[x*k],其中x等于(sqrt(5.0)+1)/2.0;而在这里满足的关系是a[k]*x=b[k]!也就是说,大的数是小的数的x倍!天哪,,简直太奥义了!!那么代码就好写多了!如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 100 + 5;
     4 typedef long long ll;
     5 typedef pair<int,int> pii;
     6 
     7 set<int> S;
     8 set<pii> S2;
     9 void init()
    10 {
    11     int now = 2;
    12     int diff = 1;
    13     S2.insert(pii(1,1));
    14     S.insert(1);
    15     for(;;)
    16     {
    17         int sz = S.size();
    18         if(sz>1000) break;
    19         if(S.find(now) == S.end())
    20         {
    21             int a = now;
    22             int b = now + diff;
    23             S2.insert(pii(a,b));
    24             S.insert(a);
    25             S.insert(b);
    26             //printf("insert !! %d %d !!
    ",a,b);
    27             now ++;
    28             diff ++;
    29         }
    30         else now ++;
    31     }
    32 }
    33 
    34 int main()
    35 {
    36     //init();
    37     /*int cnt = 0;
    38     for(set<pii>::iterator it=S2.begin();;it++)
    39     {
    40         cnt ++;
    41         if(cnt > 10 ) break;
    42         printf("%d %d
    ",(*it).first,(*it).second);
    43     }*/
    44     int T;
    45     scanf("%d",&T);
    46     while(T--)
    47     {
    48         int op ,n,m;
    49         scanf("%d%d%d",&op,&n,&m);
    50         if(op==1)
    51         {
    52             if(n%2 && m %2) puts("G");
    53             else puts("B");
    54         }
    55         else if(op==2)
    56         {
    57             if(n==m) puts("G");
    58             else puts("B");
    59         }
    60         else if(op==4)
    61         {
    62             if(n>m) swap(n,m);
    63             /*if(S2.find(pii(n,m))==S2.end())
    64             {
    65                 puts("B");
    66             }
    67             else puts("G");*/
    68             double x = (sqrt(5.0)+1.0)/2.0;
    69             if((int)(n*x)==m) puts("G");
    70             else puts("B");
    71         }
    72         else
    73         {
    74             if(n==m && n%3==1)
    75             {
    76                 puts("G");
    77             }
    78             else
    79             {
    80                 if(n>m) swap(n,m);
    81                 if(m%3==0 && m-n==1) puts("B");
    82                 else puts("D");
    83             }
    84         }
    85     }
    86 
    87 }
    奥义的威佐夫博弈

     ——————————————————————伟大的博弈论的分界线——————————————————————————————

      1010,这题完全就是高数的知识啊,然而我们太弱了,无法解出= =题解给的方法还是很吊的:

      1011,这题我们一开始卡了很久,,简直弱到爆炸- -其实很简单,因为曼哈顿距离总共就没几种,因此用一个数组来记录各种曼哈顿距离是否出现过,那么枚举在O(n^2)的过程中一旦出现重复就可以退出了;而由于抽屉原理,一旦枚举数量达到2*M必定会有重复的距离出现,那么最多的枚举数量也不过2*M。现场写的代码如下:

     1 #include<bits/stdc++.h>
     2 #define F first
     3 #define S second
     4 using namespace std;
     5 typedef pair<int,int> PII;
     6 typedef pair<long long ,long long> PLL;
     7 typedef long long ll;
     8 const double eps = 1e-8;
     9 const int N = (int)2e5 + 50;
    10 
    11 bool used[N];
    12 PII p[N];
    13 int main(){
    14     int T;
    15     cin >> T;
    16     while(T --){
    17         int n,m;
    18         scanf("%d%d",&n,&m);
    19         for(int i =  0 ; i < n ; i ++){
    20             scanf("%d%d",&p[i].F,&p[i].S);
    21         }
    22         int cnt = 0;
    23         bool f = false;
    24         memset(used,false,sizeof(used));
    25         for(int i = 0 ; i < n && !f; i ++){
    26             for(int j = i + 1 ; j < n && !f ; j ++){
    27                 int d = abs(p[i].F - p[j].F) + abs(p[i].S-p[j].S);
    28                 if(used[d]) f = true;
    29                 used[d] = true;
    30 
    31                 cnt ++;
    32                 if(cnt > N) break;
    33             }
    34         }
    35         if(f) puts("YES");
    36         else puts("NO");
    37     }
    38     return 0;
    39 }
    View Code
  • 相关阅读:
    A方法调用B方法,JVM是怎么一步一步调用的
    java ImmutableMap使用
    使用 Spring 配置动态数据源实现读写分离
    spring-boot的三种启动方式
    使用 Spring 配置动态数据源实现读写分离
    Java改变生成随机数的平均值(改变生成随机数的概率)
    微信抢红包算法实现(JAVA)
    Redis分布式锁的实现原理
    Redis和队列
    springboot自定义配置文件
  • 原文地址:https://www.cnblogs.com/zzyDS/p/5710180.html
Copyright © 2020-2023  润新知