【XJOI】NOIP2020模拟训练题2 总结


  得分情况:

   估分:

    30(T1)+100(T2)+0(T3)=130;

   实际:

    30(T1)+60(T2)+10(T3)=100;   QAQ

     是我高看自己了

 

   T1  友好数对:

  题意:

     如果一个数a能由一个数b旋转得到,那么我们称为友好数对,如12345和45123为友好数对,12345和54321不为友好数对。给出两个正整数L,R,求有多少友好数对,满足L<=a    (说实话没看懂后面这什么玩意)

     输入格式:

       第一行一个整数T,表示数据组数,每组数据两个正整数L,R。

     输出格式:

       对于每组数据,输出一个整数表示答案。 

     样例输入:

        4
        1 9
        10 40
        100 500
        1111 2222

     样例输出:

        0
        3
        156
        287

     数据范围:

       对于30%的数据满足L,R<=1000
       对于100%的数据满足L,R<=2000000,T<=30,L,R位数相同。

 

   大概理解为:   一个数a  把a分为两段  两段长度不能为零  然后把这两段交换位置得到b  要求L<=a,b<=R且a!=b   然后求有多少对这样的数

   列如 : a=12345,把a分成123、45两段  ,  然后交换得45、123   ,   粘起来就成了b=45123;

   

  分析:

      看一下数据范围  L,R<=2*1e6,T<=30;

      大概算一下2*1e6*30=6*1e7   暴力枚举完全搞得定

      因为一个数可能旋转成同一个数多次(比如  232323 )所以要判一下重

      只需要把每个数的旋转方式都来一遍 ,再判一下重,就搞定了   (没判重所以来了三十分)

                                                                                                                       

  上代码:

  

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 
 6 using namespace std;
 7 
 8 bool st[2000002];//判重用的
 9 
10 int main()
11 {
12 
13     int T;
14     scanf("%d",&T);
15     while(T--)
16     {
17         int a,b,res=0,t[10],rec[10];
18 
19         memset(st,false,sizeof(st));
20 
21         scanf("%d%d",&a,&b);
22 
23         for(int i=a;i<=b;i++)
24         {    
25             
26             int cnt=1,l=a,p=0;
27 
28             while(l)//看一下有多少位   下面分段用
29             {
30                 l/=10;
31                 cnt*=10;
32             }
33 
34             for(int j=10;j<cnt;j*=10)//枚举从哪一位分段
35             {
36 
37                 int k=i%j*(cnt/j)+i/j;
38 
39                 if(k>=a&&k<i)
40                 {
41                     if(st[k]) continue;//已经有了就不加了
42                     rec[p++]=k;
43                     st[k]=true;
44                     res++;
45                 }
46             }
47 
48             for(int j=0;j<p;j++) st[rec[j]]=false;//把刚刚判的重弄回去
49         }
50     
51         printf("%d\n",res);
52     }
53 }

    搞定


 T2 路径数:

    题意:

          Euphemia到一个N*N的药草田里采药,她从左上角的格子田(第一行,第一列)出发,要到达右下角(第N行,第N列)的格子田,每次她可以走到与当前格子有边相邻的格子去,但她不会走已经走过的格子,而且出于对美的要求,她走过的路径是关      于 左下-右上 对角线对称的。由于地势不同,在每个格子田采药都会有一个疲劳度Tij,Euphemia想知道:有多少条合法路径,可以使得她采药的疲劳度最小。

     输入格式:

          多组数据。
          每组数据第一行一个整数N,接下来N行,每行N个非零数字(1,2,3...9中一个),表示格子田的疲劳度。
          当N=0,输入结束。

     输出格式:

          对于每组数据,输出一个整数表示答案,答案%1000000009。

     样例输入:

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

     样例输出:

          2
          3

     数据范围:

          对于20%的数据满足N<=5。
          对于另外20%的数据满足N<=40。
          对于100%的数据满足N<=100,不超过50组数据。

  

  大概理解为:   从左上角走到右下角的最短路径方案数,但题目有个路径关于 左下-右上 对角线对称,大概理解为这样

 

      

        我画的好丑

  分析:

      这个题看出来是单源最短路,N有点大,所以就用堆优化的Dijkstra了

      因为有个对称,所以我们只需要把对角线以下的权值全部对称加到对角线以上,再从左上角走到对角线就OK了

 

 上代码:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<queue>
  4 #include<algorithm>
  5 #include<cstring>
  6 using namespace std;
  7 
  8 const int N=110;
  9 const int mod=1000000009;
 10 
 11 long long dis[N][N];
 12 int t[N][N],db[N][N];
 13 int n;
 14 bool book[N][N];
 15 
 16 struct sik
 17 {
 18     int x,y,w;//坐标 权值 
 19     bool operator< (const sik & f) const//重载运算符  使优先队列为小根堆 
 20     {
 21         return w>f.w; 
 22     }
 23 };
 24 
 25 int Dijkstra()
 26 {
 27     int zx[4]={0,1,0,-1},zy[4]={1,0,-1,0};//走的方位 
 28     
 29     memset(dis,0x3f,sizeof(dis));//一堆初始化 
 30     memset(db,0,sizeof(db));
 31     memset(book,false,sizeof(book));
 32     int res=0,Min=0x3f3f3f3f;
 33     
 34     priority_queue<sik> que;//优先队列 
 35     
 36     sik qu;
 37     
 38     dis[1][1]=t[1][1];
 39     db[1][1]=1;
 40     
 41     qu.x=1,qu.y=1,qu.w=t[1][1];
 42     que.push(qu); //把起点放进去 
 43     
 44     while(que.size())
 45     {
 46         sik c=que.top();
 47         que.pop();
 48         int x=c.x,y=c.y;
 49         
 50         if(dis[x][y]<=Min&&x+y==n+1) //到终点了 
 51         {
 52             if(dis[x][y]==Min) res+=db[x][y];
 53             else
 54             {
 55                 res=db[x][y];
 56             
 57                 Min=dis[x][y];
 58             }
 59             
 60         }
 61         
 62         if(book[x][y]) continue;//当前点走过了 pass掉 
 63         book[x][y]=false;
 64         
 65         for(int i=0;i<4;i++)
 66         {
 67             int x1=x+zx[i],y1=y+zy[i];
 68             
 69             if(book[x1][y1]||!x1||x1>n||!y1||y1>n) continue;
 70             
 71             if(dis[x1][y1]>dis[x][y]+t[x1][y1])
 72             {
 73                 dis[x1][y1]=dis[x][y]+t[x1][y1];
 74                 db[x1][y1]=db[x][y];
 75                 
 76                 sik o;
 77                 o.x=x1 , o.y=y1 , o.w=dis[x1][y1];//把当前这个点存进去 
 78                 que.push(o);
 79             }
 80             else if(dis[x1][y1]==dis[x][y]+t[x1][y1]) 
 81             {
 82                 db[x1][y1]+=db[x][y];
 83             }
 84         }
 85     }
 86     return res;
 87 }
 88 
 89 int main()
 90 {
 91     while(true)
 92     {
 93         memset(t,0,sizeof(t));
 94         scanf("%d",&n);
 95         if(!n) return 0;
 96         for(int i=1;i<=n;i++) 
 97         {
 98             for(int j=1;j<=n;j++)
 99             {
100                 scanf("%d",&t[i][j]);
101             
102             }
103         }
104         for(int i=1;i<=n;i++)
105         {
106             for(int j=1;j<=n-i;j++)
107             {
108                 t[i][j]+=t[n-j+1][n-i+1];//把对角线以下的加上去 
109                 
110             }
111         }
112     
113         printf("%d\n",Dijkstra());
114     }
115     return 0;
116 }

  搞定


  T3 :

      不会



   ~END~

猜你喜欢

转载自www.cnblogs.com/Arrogant-Hierarch/p/12354907.html