• 程序设计实验室暑期选拔赛 题解


    1.冬冬走迷宫
    time limit:1s
    memory limit:128 MB
    众所周知,冬冬是一个土豪以及游戏狂热玩家。最近他趁着暑假,买了许多游戏来消遣。可是当他把所有游戏都通关了以后,感到无敌是多么寂寞,必须靠经典才能满足他。于是他又玩起了走迷宫的小游戏。
    走迷宫可以简化为一个矩阵,里面含n*m个格子。有些格子是可以进入并且通过的,有些格子内含障碍物,是不能进入通过它的。我们的任务就是在给定一个起点S和一个终点T后,选择一个不经过障碍物以及走出矩阵边界的方案,把自己控制的角色从S走到T。
    然而冬冬身经百战,不知道比其他人高到哪里去了,因此他总会选择最短的路径来走完这个迷宫。可是他不能确定自己的路径是不是最短的,因此他希望你能帮助他,给出每个迷宫的最短路径长度(即从S到T经过(包含S和T)的格子数)。
    作为新晋ACMer,你能帮助冬冬完成这个任务吗?
    Input
    多组数据输入,保证格子总数不超过100w。
    第一行是两个正整数n,m,代表矩阵的高度和宽度。其中0≤n,m≤100.
    接下来n行m列,给出迷宫每个格子的情况。'S'代表起点,'T'代表终点,'#'代表障碍物,'.'代表可通行区域。
    Output
    对于每组数据,输出一行从S到T的最短路径的长度。若无从S到T的路径,则输出“Impossible”。
    Sample Input
    5 6
    S.....
    #.###.
    ##.T..
    #.###.
    #.....
    2 9
    S.#......
    ###T####.
    Sample Output
    10
    Impossible


     一道很基础的bfs题,除了迷宫的地图数组外,加入标记数组,步数数组,bfs时让每个格子向四周扩展,把没有标记的格子以及他的步数加入队列中并标记他们,还需在步数数组上记录到该点的步数,直至队列中没有元素为止(或者bfs到T点就跳出循环)。最后检查下终点T有无被标记过。没有则是Impossible,有则输出T点的步数。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<queue>
     5 #define clr_1(x) memset(x,-1,sizeof(x))
     6 #define clr(x) memset(x,0,sizeof(x))
     7 using namespace std;
     8 struct node
     9 {
    10     int x,y,step;
    11 }u,v;
    12 queue<node> que;
    13 char s[200]; 
    14 int map[200][200];
    15 int stepm[200][200];
    16 int dirx[4]={0,0,-1,1},diry[4]={1,-1,0,0};
    17 int n,m,t,k,sx,sy,tx,ty;
    18 void init()
    19 {
    20     clr(map);
    21     for(int i=1;i<=n;i++)
    22     {
    23         scanf("%s",s);
    24         for(int j=0;j<strlen(s);j++)
    25         {
    26             if(s[j]=='S')
    27             {
    28                 sx=i;
    29                 sy=j+1;    
    30                 map[i][j+1]=1;
    31             }    
    32             if(s[j]=='T')
    33             {
    34                 tx=i;
    35                 ty=j+1;
    36                 map[i][j+1]=1;                        
    37             }
    38             if(s[j]=='.')
    39             {
    40                 map[i][j+1]=1;                        
    41             }
    42         } 
    43     } 
    44     while(!que.empty())
    45         que.pop();
    46     return ;
    47 }
    48 void bfs()
    49 {
    50     while(!que.empty())
    51     {
    52         u=que.front();
    53         que.pop();
    54         for(int i=0;i<4;i++)
    55         {
    56             v=u;
    57             v.x+=dirx[i];
    58             v.y+=diry[i];
    59             v.step++;
    60             if(map[v.x][v.y]==1)
    61             {
    62                 map[v.x][v.y]=0;
    63                 stepm[v.x][v.y]=v.step;
    64                 que.push(v);
    65             }
    66         }
    67         
    68     }
    69     return ;
    70 }
    71 int main()
    72 {
    73     freopen("1.in","r",stdin);
    74     freopen("1.out","w",stdout);
    75     while(scanf("%d%d",&n,&m)!=EOF)
    76     {
    77         init();
    78         u.x=sx;
    79         u.y=sy;
    80         u.step=1;
    81         map[sx][sy]=0;
    82         que.push(u);
    83         bfs();
    84         if(map[tx][ty]==1)
    85         {
    86             printf("Impossible
    ");
    87         }
    88         else
    89         {
    90             printf("%d
    ",stepm[tx][ty]);
    91         }
    92     }
    93     return 0;        
    94 } 
    View Code

    2.冬冬沉迷走迷宫
    time limit:2s
    memory limit:128 MB
    众所周知,冬冬是一个土豪以及游戏狂热玩家。最近他趁着暑假,买了许多游戏来消遣。可是当他把所有游戏都通关了以后,感到无敌是多么寂寞,必须靠经典才能满足他。于是他又玩起了走迷宫的小游戏。
    走迷宫可以简化为一个矩阵,里面含n*m个格子。有些格子是可以进入并且通过的,有些格子内含障碍物,是不能进入通过它的。我们的任务就是在给定一个起点S和一个终点T后,选择一个不经过障碍物以及走出矩阵边界的方案,把自己控制的角色从S走到T。
    然而冬冬身经百战,不知道比其他人高到哪里去了,因此他总会选择最短的路径来走完这个迷宫。可是他不能确定自己的路径是不是最短的,并且他想知道最完美的方案一共有几种。因此他希望你能帮助他,给出每个迷宫的最短路径长度(即从S到T经过(包含S和T)的格子数)以及该长度下一共有几种不同的走法。
    作为新晋ACMer,你能帮助冬冬,完成这个任务吗?
    Input
    多组数据输入,保证不超过2组数据。
    第一行是两个正整数n,m,代表矩阵的高度和宽度。其中2≤n,m≤9。
    接下来n行m列,给出迷宫每个格子的情况。'S'代表起点,'T'代表终点,'#'代表障碍物,'.'代表可通行区域,其中S一定在左上角,也就是(0,0)的位置;T一定在右下角,也就是(n-1,m-1)的位置。
    Output
    对于每组数据,输出一行从S到T的最短路径的长度,以及该长度下的方案数,保证答案在long long范围内。若无从S到T的路径,则输出“Impossible”。
    Sample Input
    5 6
    S.....
    #.###.
    ##....
    #.###.
    #....T
    2 9
    S.#......
    ########T
    Sample Output
    10 1
    Impossible


    当初准备写个插头dp来着的,后来发现bfs也能做。把上题的所有数组保留加入方案数数组。起初S的方案数为1,其余不变。当bfs扩展到某个格子时,若该格子未被标记,记录从之前格子扩展到该格子的步数,该格子方案数为扩展到他的格子的方案数+1,加入队列。若已被标记,且记录的步数和现在扩展到该格子时的步数相同,则在原先方案数上加上这次扩展该格子获得的方案数。若记录的步数比现在扩展到该格子时的步数少,则不处理。这样做一遍bfs之后,跟上面的做法相同,检查下终点T有无被标记过。没有则是Impossible,有则输出T点的步数和方案数。

    插头dp的话左上角要建立一个独立插头,右下角要截止一个独立插头。其他格子在dp时有且仅存在一个独立插头,转移的时候和独立插头的转移一样,就是不能创建独立插头以及截止独立插头。最后dp结束检查最后一个格子步数最小的状态的方案数,若没有则是Impossible,有即为答案。

    标程用插头dp写的:

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #define clr(x) memset(x,0,sizeof(x))
      5 #define clr_1(x) memset(x,-1,sizeof(x))
      6 #define LL long long 
      7 #define HASH 10007
      8 #define STATE 1000010
      9 using namespace std;
     10 struct hashmap//hash表存状态
     11 {
     12     int size;
     13     int next[STATE],head[HASH];
     14     LL state[STATE],len[STATE];
     15     LL fas[STATE];
     16     void init()//清空 
     17     {
     18         size=0;
     19         clr_1(head);
     20     }
     21     void add(LL st,LL length,LL solu)//状态加入
     22     {
     23         int k=(st*10000+length)%HASH;
     24         for(int i=head[k];i!=-1;i=next[i])
     25             if(st==state[i] && length==len[i])
     26             {
     27                 fas[i]+=solu;
     28                 return;
     29             }
     30         next[++size]=head[k];
     31         fas[size]=solu;
     32         state[size]=st;
     33         len[size]=length;
     34         head[k]=size;
     35         return ;
     36     }
     37 }dp[2];
     38 int maped[40][40];
     39 int code[40];
     40 char s[100];
     41 void init(int n,int m)//初始化值,读入maped 
     42 {
     43     clr(maped);
     44     for(int i=1;i<=n;i++)
     45     {
     46         scanf("%s",s);
     47         for(int j=0;j<strlen(s);j++)
     48         {
     49             if(s[j]=='.' || s[j]=='S' || s[j]=='T')
     50             {
     51                 maped[i][j+1]=1;                        
     52             }
     53         } 
     54     } 
     55     return ;
     56 }
     57 void decode(LL st,int *code,int m)//解码,括号序列 
     58 {
     59     for(int i=m;i>=0;i--)
     60     {
     61         code[i]=st&3;
     62         st>>=2;
     63     }
     64     return ;
     65 }
     66 LL encode(int *code,int m)//编码,括号序列 
     67 {
     68     LL st=0;
     69     for(int i=0;i<=m;i++)
     70     {
     71         st<<=2;
     72         st|=code[i];
     73     }
     74     return st;
     75 }
     76 void shift(int *code,int m)//左移操作 
     77 {
     78     for(int i=m;i>0;i--)
     79         code[i]=code[i-1];
     80     code[0]=0;
     81     return ;
     82 }
     83 void dpblank(int i,int j,int cnt,int n,int m)//空格子状态转移 
     84 {
     85     int top,left,up;
     86     if(i==1 &&j==1)//i=1 且 j=1时加入只有下独立插头 和 右独立插头的状态 
     87     {
     88         decode(dp[cnt].state[1],code,m);
     89         if(maped[i][j+1])
     90         {
     91             code[j-1]=0;
     92             code[j]=3;
     93             dp[cnt^1].add(encode(code,m),dp[cnt].len[1]+1,dp[cnt].fas[1]);    
     94         }    
     95         if(maped[i+1][j])
     96         {
     97             code[j-1]=3;
     98             code[j]=0;
     99             if(j==m) shift(code,m);
    100             dp[cnt^1].add(encode(code,m),dp[cnt].len[1]+1,dp[cnt].fas[1]);                
    101         }
    102         return ;
    103     }
    104     if(i==n &&j==m)//i=n 且 j=m时截止单个独立插头的状态 
    105     {
    106         for(int it=1;it<=dp[cnt].size;it++)
    107         {
    108             decode(dp[cnt].state[it],code,m);
    109             code[j-1]=code[j]=0;
    110             if(j==m) shift(code,m);
    111             dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);            
    112         }
    113         return ;
    114     }
    115     for(int it=1;it<=dp[cnt].size;it++)
    116     {
    117         decode(dp[cnt].state[it],code,m);
    118         left=code[j-1];
    119         up=code[j];
    120         if(left && up)//上插头和左插头都存在 
    121         {
    122             if(left==3 || up==3)//存在一个独立插头
    123             {
    124                 if(up==2|| left==2)//若另一个插头为右括号插头,则找到对应的左括号插头变为独立插头 
    125                 {
    126                     top=0;
    127                     for(int k=j-2;k>=0;k--)
    128                     {
    129                         if(code[k]==2)
    130                             top++;
    131                         if(code[k]==1)
    132                             if(top>0)
    133                                 top--;
    134                             else
    135                                 {
    136                                     code[k]=3;
    137                                     break;
    138                                 }
    139                     }                        
    140                 }
    141                 else if(up==1 ||left==1)//若另一个插头为左括号插头,则找到对应的右括号插头变为独立插头 
    142                 {
    143                     top=0;
    144                     for(int k=j+1;k<=m;k++)
    145                     {
    146                         if(code[k]==1)
    147                             top++;
    148                         if(code[k]==2)
    149                             if(top>0)
    150                                 top--;
    151                             else
    152                                 {
    153                                     code[k]=3;
    154                                     break;
    155                                 }
    156                     }                                    
    157                 }
    158                 code[j]=code[j-1]=0;
    159                 if(j==m) shift(code,m);
    160                 dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);
    161             }
    162             else if(left!=up)//两个括号插头 
    163             {
    164                 if(left==1)//左右括号插头,不允许形成回路 
    165                     continue;
    166                 else//右左括号插头直接去掉 
    167                 {
    168                     code[j]=code[j-1]=0;
    169                     if(j==m) shift(code,m);
    170                     dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);                    
    171                  } 
    172             }
    173             else
    174             {
    175                 if(left==2)//都是左括号插头,找到对应的第一个右括号插头变为左括号插头 
    176                 {
    177                     top=0;
    178                     for(int k=j-2;k>=0;k--)
    179                     {
    180                         if(code[k]==2)
    181                             top++;
    182                         if(code[k]==1)
    183                             if(top>0)
    184                                 top--;
    185                             else
    186                                 {
    187                                     code[k]=2;
    188                                     break;
    189                                 }
    190                     }
    191                 }
    192                 else//都是右括号插头,找到对应的第一个左括号插头变为右括号插头  
    193                 {
    194                     top=0;
    195                     for(int k=j+1;k<=m;k++)
    196                     {
    197                         if(code[k]==1)
    198                             top++;
    199                         if(code[k]==2)
    200                             if(top>0)
    201                                 top--;
    202                             else
    203                                 {
    204                                     code[k]=1;
    205                                     break;
    206                                 }
    207                     }                
    208                 }
    209                 code[j]=code[j-1]=0;
    210                 if(j==m) shift(code,m);
    211                 dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);
    212             }
    213         }
    214         else if(left || up)//仅有一个插头,则延伸插头 
    215         {
    216             if(left) top=left;
    217             else top=up;
    218             if(maped[i][j+1])//右延伸插头 
    219             {
    220                 code[j-1]=0;
    221                 code[j]=top;
    222                 dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);                
    223             }
    224             if(maped[i+1][j])//下延伸插头 
    225             {
    226                 code[j-1]=top;
    227                 code[j]=0;
    228                 if(j==m) shift(code,m);
    229                 dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);                
    230             }
    231         }
    232         else//没有插头 
    233         {
    234             if(maped[i+1][j] && maped[i][j+1])//下插头和左插头 
    235             {
    236                 code[j-1]=1;
    237                 code[j]=2;
    238                 dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);    
    239             }
    240             //可经过可不经过点则可以保持原样,没有插头 
    241             code[j-1]=code[j]=0;
    242             if(j==m) shift(code,m);
    243             dp[cnt^1].add(encode(code,m),dp[cnt].len[it],dp[cnt].fas[it]);                            
    244         }        
    245     }
    246     return ;
    247 }void dpblock(int i,int j,int cnt,int n,int m)//障碍格子状态转移 
    248 {
    249     for(int it=1;it<=dp[cnt].size;it++)
    250     {
    251         decode(dp[cnt].state[it],code,m);
    252         if(j==m) shift(code,m);
    253         dp[cnt^1].add(encode(code,m),dp[cnt].len[it],dp[cnt].fas[it]);
    254     }
    255     return ;
    256 } 
    257 void solve(int n,int m)
    258 {
    259     int cnt=0;
    260     LL ans,minfas;
    261     dp[cnt].init();
    262     dp[cnt].add(0,0,1);
    263     for(int i=1;i<=n;i++)
    264     {
    265         for(int j=1;j<=m;j++)
    266         {
    267             dp[cnt^1].init();
    268             if(maped[i][j]==1) 
    269                 dpblank(i,j,cnt,n,m);
    270             else
    271                 dpblock(i,j,cnt,n,m);
    272             cnt^=1;
    273 /*            for(int it=1;it<=dp[cnt].size;it++)
    274             {
    275                 decode(dp[cnt].state[it],code,m);
    276                 for(int k=0;k<=m;k++)
    277                     printf("%d:%d ",k,code[k]);
    278                 printf("fas:%lld
    ",dp[cnt].fas[it]);
    279             }
    280             printf("
    "); */
    281         }
    282     }
    283     if(dp[cnt].size==0)
    284         printf("Impossible
    ");
    285     else
    286     {
    287         ans=0x3f3f3f3f;
    288            for(int i=1;i<=dp[cnt].size;i++)
    289            {
    290                if(dp[cnt].len[i]<ans)
    291                {
    292                    ans=dp[cnt].len[i];
    293                    minfas=dp[cnt].fas[i];
    294             }
    295            }
    296            printf("%lld %lld
    ",ans,minfas);
    297     }
    298     return ; 
    299 }
    300 int main()
    301 {
    302     int n,m,kase=0;
    303     while(scanf("%d%d",&n,&m)!=EOF)
    304     {
    305         init(n,m);
    306         solve(n,m); 
    307     }
    308     return 0;
    309 }
    View Code

    3.数论只会GCD

    time limit:3s

    memory limit:512 MB

    林学姐从初中就开始参加OI(信息学竞赛),并且当时花了好久写出来了.可爱的林学姐最喜欢GCD问题了,如果你做出来这道题,一定能得到林学姐的芳心.
    定义函数:对于正整数,H(x)表示x的素数因子的种类.
    例如:2=2, H(2)=1, 2的素数因子只有一种; 6=2*3, H(6)=2, 6的素数因子有2,3两种; 9=3*3, H(9)=1, 9的素数因子只有一种; 12=2*2*3, H(9)=2, 12的素数因子有两种.
    每次查询一个范围[L,R],求MAX(GCD(H(i),H(j))),(L<=i<j<<=R).

    GCD(a,b)是指a,b两个数最大公约数

    Input
    多组数据,第一个数为查询次数T,接下来T行每行有一个L,R.
    T<=1000000
    1<L,R<=1000000
    Output
    一行,MAX(GCD(H(i),H(j)))
    Sample Input
    2

    2 3

    2 5
    Sample Output

    1

    1


    看起来100w挺大的,然而每个数包含的不同的质数因子个数算下最多才7个(2*3*5*7*11*13*17*19=9,699,690),写一个线性筛O(n)的复杂度算下每个数不同质数因子个数,或者埃氏筛法求解不超过O(7*n)的时间复杂度。题目时间放宽写埃氏筛法也能过。把100w的数的进行预处理,并且统计下含质因子数量不同的数的个数的前缀和。之后后再进行读入,用常数的时间算出MAX(GCD(H(i),H(j))),(L<=i<j<<=R)即可,一堆if判断下就行。

     1 // code by xad
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4  
     5 int F[1000010];
     6 bool flag[1000010];
     7 int S[7][10000010];
     8 void init()
     9 {
    10     for(int i = 2; i <= 1000000; i++) if(!flag[i]){
    11         F[i]++;
    12         for(int j = i + i; j <= 1000000; j += i) {
    13             flag[j] = true;    
    14             F[j]++;
    15         }
    16     }
    17     for(int i = 2; i <= 1000000; i++) {
    18         for(int j = 0; j < 7; j++) {
    19             S[j][i] = S[j][i - 1] + (F[i] == j + 1);
    20         }
    21     }
    22 }
    23 int main()
    24 {
    25     init();
    26     int T, l, r;
    27     scanf("%d", &T);
    28     while(T--){
    29         scanf("%d%d", &l, &r);
    30         assert(l != r);
    31         int cnt[8];
    32         memset(cnt, 0, sizeof(cnt));
    33         for(int i = 0; i < 7; i++) {
    34             cnt[i + 1] = S[i][r] - S[i][l - 1];
    35         }
    36         int ret = 1;
    37         if(cnt[2] + cnt[4] + cnt[6]>=2) ret = 2;
    38         if(cnt[3] + cnt[6] >= 2) ret = 3;
    39         if(cnt[4] >= 2) ret = 4;
    40         if(cnt[5] >= 2) ret = 5;
    41         if(cnt[6] >= 2) ret = 6;
    42         if(cnt[7] >= 2) ret = 7;
    43         printf("%d
    ", ret);
    44     }
    45     return 0;
    46 }
    View Code

    4.宣区校内快递点

    time limit:1s

    memory limit:128MB

    每次都从校外取快递对同学们来说是一件很累的事情,因此快递点的老板们决定在校内设立几个快递点,但要遵守一个规则就是:使得每个宿舍楼都可以通过在道路上最多d公里到达一个快递点。宿舍楼的位置在本题里是假设的,与真实情况无关。
    假设全校一共有n个宿舍,编号从1到n,初始时有n  - 1条道路相连。所有道路长1公里。最初可以从一个宿舍到使用这些道路连接的任何其他宿舍。本校一共要设立k个快递点,每个快递点位置就是在n个宿舍中的一个。特别是宿舍整个网络结构符合上述快递老板们遵守的规则。另请注意,一个宿舍可以有多个快递点。
    然而,冬冬同学感觉没必要建立n-1条路,为了尽可能多地关闭道路来尽量减少道路维护成本,各位大佬快来帮助冬冬找到最多可以关闭的道路。但我们始终都要遵守一个规则,就是使得每个宿舍楼都可以通过在道路上最多d公里到达一个快递点。

    Input
    第一行包含三个整数n,ķ,和d(2≤  n≤3·10^5,1≤  ķ  ≤3*10^5,0≤  d  ≤  n - 1)分别表示宿舍的数量,设立快递点的数量,上述规则中距离限制在d公里内。
    第二行包含ķ个整数,p1,  p2,...,  pķ(1≤  pi≤  n) 表示快递点位于宿舍的编号。
    在我以下的第n  - 1行包含两个整数u和v (1≤ u, v  ≤ n,u ≠  v)表示宿舍u和v间建立一条道路,分别为道路1到道路n-1。从1开始编号(1,2,3…)
    只有通过道路才可以从一个宿舍到任何其他宿舍。另外,从任何一个宿舍都可以到达d公里内的一个快递点。
    Output

    输出包括一行,打印一个整数,表示可以被关闭道路的最大数量。
    注:此题使用多组输入。

    Sample Input 

    6 2 4

    1 6

    1 2

    2 3

    3 4

    4 5

    5 6

    6 3 2

    1 5 6

    1 2

    1 3

    1 4

    1 5

    5 6

    Sample Output

    1

    2


    这题有点问题。本意是让大家把所有快递点加入到队列中,做一遍bfs。并且对bfs中访问过的点做个标记,然后在bfs中删去边的终点为标记点的边,剩下的就是删去边数最大时的边的数量了。

     1 //code by fhs
     2 #include <bits/stdc++.h>
     3 #include <iostream>
     4 #include <vector>
     5 #include <algorithm>
     6 #include <map>
     7 #include <set>
     8 #include <queue>
     9  
    10 using namespace std;
    11  
    12 typedef long long int64;
    13 const int kMaxN= 3e5+10;
    14 const int kInf = (1<<30);
    15  
    16 int n, k, d;
    17 bool police[kMaxN];
    18 vector<int> T[kMaxN];
    19 vector<pair<int,int>> edges;
    20 int from[kMaxN];
    21  
    22 void bfs() {
    23     queue<int> Q;
    24     for (int i = 1; i <= n; ++i) {
    25         if (police[i]) {
    26             from[i] = i;
    27             Q.push(i);
    28         }
    29     }
    30      
    31     while (!Q.empty()) {
    32         int x = Q.front();
    33         Q.pop();
    34          
    35         for (int i = 0;i < T[x].size();++ i) {
    36             int y = T[x][i];
    37             if (from[y] == 0) {
    38                 from[y] = from[x];
    39                 Q.push(y);
    40             }
    41         }
    42     }
    43 }
    44  
    45 void solve() {
    46     memset(police,0,sizeof(police));
    47     for(int i = 0;i <= kMaxN;++ i)
    48         T[i].clear();
    49     edges.clear();
    50     memset(from,0,sizeof(from));
    51     scanf("%d %d %d", &n, &k, &d);
    52     for (int i = 1; i <= k; ++i) {
    53         int x;
    54         scanf("%d", &x);
    55         police[x] = true;
    56     }
    57      
    58     for (int i = 1; i < n; ++i) {
    59         int x, y;
    60         scanf("%d %d", &x, &y);
    61         T[x].push_back(y);
    62         T[y].push_back(x);
    63         edges.push_back({x, y});
    64     }
    65     bfs();
    66     vector<int> sol;
    67     for (int i = 0; i < edges.size(); ++i) {
    68         auto& edge = edges[i];
    69         if (from[edge.first] != from[edge.second]) {
    70             sol.push_back(i+1);
    71         }
    72     }
    73     cout << sol.size() << "
    ";
    74 }
    75  
    76 int main() {
    77     int tests = 10;
    78      
    79     for (;tests; --tests) {
    80         solve();
    81         // reset();
    82     }
    83 }
    View Code

    5.林喵喵算数

    time limit:1s

    memory limit:128MB

    给你两个八进制数,你需要在八进制计数法的情况下计算a-b。
    如果结果为负数,你应该使用负八进制数表示。

    Input
    输入的第一个数字为T,表式测试的样例的组数(1 <= T <= 1000)。
    每组数据包括两个八进制数a,b.
    Output

    输出计算结果,同样八进制表示。如果结果为负数,你应该使用负八进制数表示。

    Sample Input 

    2

    176 7

    4 14

    Sample Output

    167

    -10


    水题签到题。

     1 //code by xad
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<algorithm>
     6 using namespace std;
     7 typedef long long ll;
     8 ll c[1111];
     9 ll work1(ll t)
    10 {
    11     ll ans=0,temp=1;
    12     ll num=t;
    13     while(num) {
    14         ans+=num%10*temp;
    15         temp*=8;
    16         num/=10;
    17     }
    18     return ans;
    19 }
    20  
    21 int work2(ll t)
    22 {
    23     ll num=t;
    24     int k=0;
    25     while(num) {
    26         c[++k]=num%8;
    27         num/=8;
    28     }
    29     return k;
    30 }
    31  
    32 int main()
    33 {
    34     int k,T,i,j,flag;
    35     ll a,b,num;
    36     cin>>T;
    37     while(T--) {
    38         cin>>a>>b;
    39         if(a>=b) flag=1;
    40         else flag=-1;
    41         num=work1(a)-work1(b);
    42         if(num==0) {
    43             cout<<"0"<<endl;
    44             continue;
    45         }
    46         k=work2(num*flag);
    47         if(flag==-1) cout<<"-";
    48         for(i=k;i>=1;i--) cout<<c[i];
    49         cout<<endl;
    50     }
    51     return 0;
    52 }
    View Code

    6.签到题

    time limit:1s

    memory limit:128MB

    在计算机网络考试中, 黑帅男神看到一个将IP网络分类的题, 精通C++的他瞬间写出了几行代码成功解决了这个问题

    请解析IP地址和对应的掩码,进行分类识别。要求按照A/B/C/D/E类地址归类.

    现在假设将所有的IP地址划分为 A,B,C,D,E五类

    A类地址1.0.0.0~126.255.255.255;

    B类地址128.0.0.0~191.255.255.255;

    C类地址192.0.0.0~223.255.255.255;

    D类地址224.0.0.0~239.255.255.255;

    E类地址240.0.0.0~255.255.255.255

    请对输入的IP地址进行分类

    Input
    多组,第一行是一个T(T<=100000)
    接下来T行,每行一个ip地址(不保证正确)
    Output

    在上面5类中则输出对应类型
    不属于上述类型或IP错误则输出”nope”(不含引号)

    Sample Input 

    2

    222.195.8.207

    127.0.0.1

    Sample Output

    C

    nope


     也是水题签到题。

     1 //code by xad
     2 #include<cstdio>
     3 #include<iostream>
     4 using namespace std;
     5  
     6 int main(){
     7     int T;
     8     scanf("%d",&T);
     9     for(int i=0;i<T;i++){
    10         int a,b,c,d;
    11         scanf("%d.%d.%d.%d",&a,&b,&c,&d);
    12         if(a>=1&&a<=126&&b>=0&&b<=255&&c>=0&&c<=255&&d>=0&&d<=255){
    13             printf("A
    ");
    14         }
    15         else if(a>=128&&a<=191&&b>=0&&b<=255&&c>=0&&c<=255&&d>=0&&d<=255){
    16             printf("B
    ");
    17         }
    18         else if(a>=192&&a<=223&&b>=0&&b<=255&&c>=0&&c<=255&&d>=0&&d<=255){
    19             printf("C
    ");
    20         } 
    21         else if(a>=224&&a<=239&&b>=0&&b<=255&&c>=0&&c<=255&&d>=0&&d<=255){
    22             printf("D
    ");
    23         }   
    24         else if(a>=240&&a<=255&&b>=0&&b<=255&&c>=0&&c<=255&&d>=0&&d<=255){
    25             printf("E
    ");
    26         }
    27         else{
    28             printf("nope
    ");
    29         }
    30          
    31     }
    32      
    33     return 0;
    34 }
    View Code

    7.冬冬不喜欢迷宫
    time limit:2s
    memory limit:128 MB
    众所周知,冬冬是一个土豪以及游戏狂热玩家。最近他趁着暑假,买了许多游戏来消遣。可是当他把所有游戏都通关了以后,感到无敌是多么寂寞,必须靠经典才能满足他。于是他又玩起了走迷宫的小游戏。
    走迷宫可以简化为一个矩阵,里面含n*m个格子。有些格子是可以进入并且通过的,有些格子内含障碍物,是不能进入通过它的。我们的任务就是在给定一个起点S和一个终点T后,选择一个不经过障碍物以及走出矩阵边界的方案,把自己控制的角色从S走到T。
    然而冬冬身经百战,不知道比其他人高到哪里去了,因此他总想选择最短的路径来走完这个迷宫。可是冬冬的策略总是不能使他达到最优,帅宝宝也告诉他他的路径是第二短的。冬冬很生气。他一直找不出来他的策略哪里有漏洞。
    为了安慰冬冬,你能告诉他第二短的路径有多长,以及有多少条这样的路径吗?
    Input
    多组数据输入,保证不超过2组数据。
    第一行是两个正整数n,m,代表矩阵的高度和宽度。其中2≤n,m≤9。
    接下来n行m列,给出迷宫每个格子的情况。'S'代表起点,'T'代表终点,'#'代表障碍物,'.'代表可通行区域,其中S一定在左上角,也就是(0,0)的位置;T一定在右下角,也就是(n-1,m-1)的位置。
    Output
    对于每组数据,输出一行从S到T的第二短路径的长度,以及该长度下的方案数,保证答案在long long范围内。若无从S到T的长度第二短的路径,则输出“Impossible”。
    Sample Input
    5 6
    S.....
    #.###.
    ##....
    #.##..
    #....T
    2 9
    S.#......
    ########T
    Sample Output
    12 3
    Impossible


    防新生ak题,简单粗暴插头dp,跟第二题的插头dp想法一样,然后最后输出的是步数第二大的状态 以及该状态下的方案数。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #define clr(x) memset(x,0,sizeof(x))
      5 #define clr_1(x) memset(x,-1,sizeof(x))
      6 #define LL long long 
      7 #define HASH 10007
      8 #define STATE 1000010
      9 using namespace std;
     10 struct hashmap//hash表存状态
     11 {
     12     int size;
     13     int next[STATE],head[HASH];
     14     LL state[STATE],len[STATE];
     15     LL fas[STATE];
     16     void init()//清空 
     17     {
     18         size=0;
     19         clr_1(head);
     20     }
     21     void add(LL st,LL length,LL solu)//状态加入
     22     {
     23         int k=(st*10000+length)%HASH;
     24         for(int i=head[k];i!=-1;i=next[i])
     25             if(st==state[i] && length==len[i])
     26             {
     27                 fas[i]+=solu;
     28                 return;
     29             }
     30         next[++size]=head[k];
     31         fas[size]=solu;
     32         state[size]=st;
     33         len[size]=length;
     34         head[k]=size;
     35         return ;
     36     }
     37 }dp[2];
     38 int maped[40][40];
     39 int code[40];
     40 char s[100];
     41 void init(int n,int m)//初始化值,读入maped 
     42 {
     43     clr(maped);
     44     for(int i=1;i<=n;i++)
     45     {
     46         scanf("%s",s);
     47         for(int j=0;j<strlen(s);j++)
     48         {
     49             if(s[j]=='.' || s[j]=='S' || s[j]=='T')
     50             {
     51                 maped[i][j+1]=1;                        
     52             }
     53         } 
     54     } 
     55     return ;
     56 }
     57 void decode(LL st,int *code,int m)//解码,括号序列 
     58 {
     59     for(int i=m;i>=0;i--)
     60     {
     61         code[i]=st&3;
     62         st>>=2;
     63     }
     64     return ;
     65 }
     66 LL encode(int *code,int m)//编码,括号序列 
     67 {
     68     LL st=0;
     69     for(int i=0;i<=m;i++)
     70     {
     71         st<<=2;
     72         st|=code[i];
     73     }
     74     return st;
     75 }
     76 void shift(int *code,int m)//左移操作 
     77 {
     78     for(int i=m;i>0;i--)
     79         code[i]=code[i-1];
     80     code[0]=0;
     81     return ;
     82 }
     83 void dpblank(int i,int j,int cnt,int n,int m)//空格子状态转移 
     84 {
     85     int top,left,up;
     86     if(i==1 &&j==1)//i=1 且 j=1时加入只有下独立插头 和 右独立插头的状态 
     87     {
     88         decode(dp[cnt].state[1],code,m);
     89         if(maped[i][j+1])
     90         {
     91             code[j-1]=0;
     92             code[j]=3;
     93             dp[cnt^1].add(encode(code,m),dp[cnt].len[1]+1,dp[cnt].fas[1]);    
     94         }    
     95         if(maped[i+1][j])
     96         {
     97             code[j-1]=3;
     98             code[j]=0;
     99             if(j==m) shift(code,m);
    100             dp[cnt^1].add(encode(code,m),dp[cnt].len[1]+1,dp[cnt].fas[1]);                
    101         }
    102         return ;
    103     }
    104     if(i==n &&j==m)//i=n 且 j=m时截止单个独立插头的状态 
    105     {
    106         for(int it=1;it<=dp[cnt].size;it++)
    107         {
    108             decode(dp[cnt].state[it],code,m);
    109             code[j-1]=code[j]=0;
    110             if(j==m) shift(code,m);
    111             dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);            
    112         }
    113         return ;
    114     }
    115     for(int it=1;it<=dp[cnt].size;it++)
    116     {
    117         decode(dp[cnt].state[it],code,m);
    118         left=code[j-1];
    119         up=code[j];
    120         if(left && up)//上插头和左插头都存在 
    121         {
    122             if(left==3 || up==3)//存在一个独立插头
    123             {
    124                 if(up==2|| left==2)//若另一个插头为右括号插头,则找到对应的左括号插头变为独立插头 
    125                 {
    126                     top=0;
    127                     for(int k=j-2;k>=0;k--)
    128                     {
    129                         if(code[k]==2)
    130                             top++;
    131                         if(code[k]==1)
    132                             if(top>0)
    133                                 top--;
    134                             else
    135                                 {
    136                                     code[k]=3;
    137                                     break;
    138                                 }
    139                     }                        
    140                 }
    141                 else if(up==1 ||left==1)//若另一个插头为左括号插头,则找到对应的右括号插头变为独立插头 
    142                 {
    143                     top=0;
    144                     for(int k=j+1;k<=m;k++)
    145                     {
    146                         if(code[k]==1)
    147                             top++;
    148                         if(code[k]==2)
    149                             if(top>0)
    150                                 top--;
    151                             else
    152                                 {
    153                                     code[k]=3;
    154                                     break;
    155                                 }
    156                     }                                    
    157                 }
    158                 code[j]=code[j-1]=0;
    159                 if(j==m) shift(code,m);
    160                 dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);
    161             }
    162             else if(left!=up)//两个括号插头 
    163             {
    164                 if(left==1)//左右括号插头,不允许形成回路 
    165                     continue;
    166                 else//右左括号插头直接去掉 
    167                 {
    168                     code[j]=code[j-1]=0;
    169                     if(j==m) shift(code,m);
    170                     dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);                    
    171                  } 
    172             }
    173             else
    174             {
    175                 if(left==2)//都是左括号插头,找到对应的第一个右括号插头变为左括号插头 
    176                 {
    177                     top=0;
    178                     for(int k=j-2;k>=0;k--)
    179                     {
    180                         if(code[k]==2)
    181                             top++;
    182                         if(code[k]==1)
    183                             if(top>0)
    184                                 top--;
    185                             else
    186                                 {
    187                                     code[k]=2;
    188                                     break;
    189                                 }
    190                     }
    191                 }
    192                 else//都是右括号插头,找到对应的第一个左括号插头变为右括号插头  
    193                 {
    194                     top=0;
    195                     for(int k=j+1;k<=m;k++)
    196                     {
    197                         if(code[k]==1)
    198                             top++;
    199                         if(code[k]==2)
    200                             if(top>0)
    201                                 top--;
    202                             else
    203                                 {
    204                                     code[k]=1;
    205                                     break;
    206                                 }
    207                     }                
    208                 }
    209                 code[j]=code[j-1]=0;
    210                 if(j==m) shift(code,m);
    211                 dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);
    212             }
    213         }
    214         else if(left || up)//仅有一个插头,则延伸插头 
    215         {
    216             if(left) top=left;
    217             else top=up;
    218             if(maped[i][j+1])//右延伸插头 
    219             {
    220                 code[j-1]=0;
    221                 code[j]=top;
    222                 dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);                
    223             }
    224             if(maped[i+1][j])//下延伸插头 
    225             {
    226                 code[j-1]=top;
    227                 code[j]=0;
    228                 if(j==m) shift(code,m);
    229                 dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);                
    230             }
    231         }
    232         else//没有插头 
    233         {
    234             if(maped[i+1][j] && maped[i][j+1])//下插头和左插头 
    235             {
    236                 code[j-1]=1;
    237                 code[j]=2;
    238                 dp[cnt^1].add(encode(code,m),dp[cnt].len[it]+1,dp[cnt].fas[it]);    
    239             }
    240             //可经过可不经过点则可以保持原样,没有插头 
    241             code[j-1]=code[j]=0;
    242             if(j==m) shift(code,m);
    243             dp[cnt^1].add(encode(code,m),dp[cnt].len[it],dp[cnt].fas[it]);                            
    244         }        
    245     }
    246     return ;
    247 }void dpblock(int i,int j,int cnt,int n,int m)//障碍格子状态转移 
    248 {
    249     for(int it=1;it<=dp[cnt].size;it++)
    250     {
    251         decode(dp[cnt].state[it],code,m);
    252         if(j==m) shift(code,m);
    253         dp[cnt^1].add(encode(code,m),dp[cnt].len[it],dp[cnt].fas[it]);
    254     }
    255     return ;
    256 } 
    257 void solve(int n,int m)
    258 {
    259     int cnt=0;
    260     LL ans,minfas,secans,secminfas;
    261     dp[cnt].init();
    262     dp[cnt].add(0,0,1);
    263     for(int i=1;i<=n;i++)
    264     {
    265         for(int j=1;j<=m;j++)
    266         {
    267             dp[cnt^1].init();
    268             if(maped[i][j]==1) 
    269                 dpblank(i,j,cnt,n,m);
    270             else
    271                 dpblock(i,j,cnt,n,m);
    272             cnt^=1;
    273 /*            for(int it=1;it<=dp[cnt].size;it++)
    274             {
    275                 decode(dp[cnt].state[it],code,m);
    276                 for(int k=0;k<=m;k++)
    277                     printf("%d:%d ",k,code[k]);
    278                 printf("fas:%lld
    ",dp[cnt].fas[it]);
    279             }
    280             printf("
    "); */
    281         }
    282     }
    283     if(dp[cnt].size<=1)
    284         printf("Impossible
    ");
    285     else
    286     {
    287         ans=secans=0x3f3f3f3f;
    288            for(int i=1;i<=dp[cnt].size;i++)
    289            {
    290                if(dp[cnt].len[i]<ans)
    291                {
    292                    ans=dp[cnt].len[i];
    293                    minfas=dp[cnt].fas[i];
    294             }
    295            }
    296            for(int i=1;i<=dp[cnt].size;i++)
    297            {
    298                if(dp[cnt].len[i]<secans && dp[cnt].len[i]!=ans)
    299                {
    300                    secans=dp[cnt].len[i];
    301                    secminfas=dp[cnt].fas[i];
    302             }
    303            }
    304            printf("%lld %lld
    ",secans,secminfas);
    305     }
    306     return ;
    307 }
    308 int main()
    309 {
    310     int n,m,kase=0;
    311 /*    freopen("11.in","r",stdin);
    312     freopen("11.out","w",stdout);*/
    313     while(scanf("%d%d",&n,&m)!=EOF)
    314     {
    315         init(n,m);
    316         solve(n,m); 
    317     }
    318     return 0;
    319 }
    View Code

    8.MCC的考验
    time limit:1s
    memory limit:128 MB
    MCC男神听说新一期的选拔赛要开始了,给各位小伙伴们带来了一道送分题,如果你做不出来,MCC会很伤心的。
    给定一个大小为n的非空整数数组,现在定义一种操作,每一步操作会将该数组中的n-1个数同时加1,问最少进行多少步操作后,可以使得数组里的每一个数字都相等。
    例如,一个n为3的数组[1,2,3],最少进行3步操作后,可以变为[4,4,4]
    过程如下:[1,2,3] => [2,3,3] => [3,4,3] => [4,4,4]
    Input
    第一行为一个整数n,代表数组个数。1<=n<=1,000,000
    第二行为每个数组的数字a[i],1<=a[i]<=1000
    Output
    输出需要的最少操作数。
    Sample Input
    3
    2 3 4
    Sample Output
    3


    让n-1个数组的数字同时+1,相当于让一个数组的数字-1。计算下每个数组数字与数字最小的数组的数字的差,然后把他们求和后即为操作数。

     1 //code by mcc
     2 #include<iostream>
     3 #include<cmath>
     4 #include<vector>
     5 #include<utility>
     6 #include<algorithm>
     7 #include<string>
     8 #include<queue>
     9 #include<set>
    10 #include<map>
    11 #include<stack>
    12 using namespace std ;
    13 int nums[1000010];
    14 int main()
    15 {
    16 /*    freopen("1.in","r",stdin);
    17     freopen("1.out","w",stdout); */
    18     int len ;
    19     cin>>len ;
    20     for (int i = 0; i < len;i++ ){
    21        cin>>nums[i] ;
    22     }
    23     if (len <= 1){
    24         cout<<0<<endl ;
    25         return 0 ;
    26     }
    27     int Min = nums[0] ;
    28     int sum = 0 ;
    29     for (int i = 0; i < len;i++ ){
    30         sum += nums[i] ;
    31         if (nums[i] < Min)
    32            Min = nums[i] ;
    33     }
    34     cout<<sum-Min*len<<endl ;
    35     return 0;
    36 }
    View Code

     附上本次比赛链接:http://xcacm.hfut.edu.cn/contest.php?cid=1014

  • 相关阅读:
    高德地图SDK大致使用
    AFNetworking 使用
    蓝牙相关
    svn 常用命令
    通过AutoLayout显示三个等宽视图
    适配相关 --AutoLayout ---SizeClass
    常用网页
    UIViewController加载过程
    UIApplication相关
    实现消息转发功能(调用非自己类方法)
  • 原文地址:https://www.cnblogs.com/wujiechao/p/7182450.html
Copyright © 2020-2023  润新知