【NOIp】NOIp2013

NOIp 2013

day 1 T1 转圈游戏

标签:数论

 挺显然$ans=(x+m*{10^k})mod n$

 快速幂处理$10^k$

code

 1 //
 2 //  main.cpp
 3 //  Luogu
 4 //
 5 //  Created by gengyf on 2019/5/9.
 6 //  Copyright © 2019 yifan Geng. All rights reserved.
 7 //
 8 
 9 #include<bits/stdc++.h>
10 using namespace std;
11 #define Mod 19260817
12 int n,m,k,x;
13 int fast(int a,int b){
14     int re=1,t=a;
15     while(b){
16         if(b&1)re=re*t%n;
17         t=t*t%n;
18         b>>=1;
19     }
20     return re;
21 }
22 int main(){
23     scanf("%d%d%d%d",&n,&m,&k,&x);
24     printf("%d",(x%n+fast(10,k)%n*m%n)%n);
25     return 0;
26 }
T1

day 1 T2 火柴排队

标签:归并排序(?

求$minsum{(a_i-b_i)^2}$相当于求$a_i-b_i$的最小值,也就是让a和b的每一根火柴高度差都最小,问最少的交换次数

那么问题是:怎么把一个乱序序列排成另一个乱序序列

新建一个序列$c_i$ 令 $c_{a_i}=b_i$ 就相当于以$a_i$为关键字对$b_i$排序

如果此时a序列和b序列一样,也就是$c_i=i$,所以我们只需把c升序排列,求最少交换次数(逆序对数)即可

而归并排序就可以完美解决


简单提一下:归并排序

归并排序是速度仅次于快排的排序稳定算法,可以用来排序(废话)和求逆序对

排序算法可视化 <- 超级直观


code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 namespace gengyf{
 4 #define ll long long
 5   inline int read(){
 6     int x=0,f=1;char s=getchar();
 7     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
 8     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
 9     return f*x;
10   }
11   const int maxn=1e5+10;
12   const int mod=99999997;
13   struct node{
14     int y,x;
15   }a[maxn],b[maxn];
16   int c[maxn],d[maxn],n,cnt;
17   void merge(int l,int r){
18     if(l>=r)return ;
19     int mid=(l+r)>>1;
20     merge(l,mid);merge(mid+1,r);
21     int i=l,j=mid+1,k=l;
22     while(i<=mid&&j<=r){
23       if(c[i]<=c[j]){
24         d[k++]=c[i++];
25       }
26       else {
27         d[k++]=c[j++];
28         cnt+=mid-i+1;
29         cnt%=mod;
30       }
31     }
32     while(i<=mid){
33       d[k++]=c[i++];
34     }
35     while(j<=r){
36       d[k++]=c[j++];
37     }
38     for(int i=l;i<=r;i++) c[i]=d[i];
39   }
40   bool cmp(node a,node b){
41     return a.x<b.x;
42   }
43   int main(){
44     n=read();
45     for(int i=1;i<=n;i++){
46       a[i].x=read();a[i].y=i;
47     }
48     for(int i=1;i<=n;i++){
49       b[i].x=read();b[i].y=i;
50     }
51     sort(a+1,a+1+n,cmp);
52     sort(b+1,b+1+n,cmp);
53     for(int i=1;i<=n;i++){
54       c[b[i].y]=a[i].y;
55     }
56     merge(1,n);
57     printf("%d",cnt);
58     return 0;
59   }
60 }
61 signed main(){
62   gengyf::main();
63   return 0;
64 }
T2

day 1 T3 货车运输

标签:图论

最大生成树+LCA

发现小边是不会被走的,建一棵最大生成树,再考虑如何求x,y之间最小边权的最大值,可以想到求x,y分别到LCA(x,y)的最大边权,取min

code

  1 //
  2 //  main.cpp
  3 //  Luogu
  4 //
  5 //  Created by gengyf on 2019/7/7.
  6 //  Copyright ? 2019 yifan Geng. All rights reserved.
  7 //
  8 //Luogu P1967
  9 #include<bits/stdc++.h>
 10 using namespace std;
 11 const int maxn=100010;
 12 const int maxm=500010;
 13 struct edge{
 14     int to,nxt,dis;
 15 }e[maxm<<1];
 16 struct edg{
 17     int u,v,w;
 18 }ed[maxm];
 19 int n,m,q,cnt;
 20 int head[maxn],fa[maxn],dep[maxn];
 21 int f[maxn][30],dis[maxn][20];
 22 bool vis[maxn];
 23 inline void add(int u,int v,int w){
 24     e[++cnt].nxt=head[u];
 25     head[u]=cnt;
 26     e[cnt].to=v;
 27     e[cnt].dis=w;
 28 }
 29 bool cmp(edg x,edg y){
 30     return x.w>y.w;
 31 }
 32 int get(int x){
 33     return fa[x]==x?x:fa[x]=get(fa[x]);
 34 }
 35 void kruskal(){
 36     for(int i=1;i<=m;i++){
 37         int x=ed[i].u,y=ed[i].v;
 38         if(get(x)!=get(y)){
 39             fa[get(y)]=get(x);
 40             add(x,y,ed[i].w);
 41             add(y,x,ed[i].w);
 42         }
 43     }
 44 }
 45 void dfs(int x){
 46     vis[x]=1;
 47     for(int i=head[x];i;i=e[i].nxt){
 48         int y=e[i].to;
 49         if(vis[y]) continue;
 50         dep[y]=dep[x]+1;
 51         f[y][0]=x;
 52         dis[y][0]=e[i].dis;
 53         dfs(y);
 54     }
 55 }
 56 int lca(int x,int y){
 57     int ans=0x3f3f3f;
 58     if(x==y) return 0;
 59     if(dep[x]<dep[y]) swap(x,y);
 60     int t=(int)(log(dep[x])/log(2));
 61     for(int i=t;i>=0;i--){
 62         if(dep[x]-(1<<i)>=dep[y]){
 63             ans=min(ans,dis[x][i]);
 64             x=f[x][i];
 65         }
 66     }
 67     if(x==y) return ans;
 68     for(int i=t;i>=0;i--){
 69         if(f[x][i]&&f[x][i]!=f[y][i]) {
 70             ans=min(ans,min(dis[x][i],dis[y][i]));
 71             x=f[x][i],y=f[y][i];
 72         }
 73     }
 74     ans=min(ans,min(dis[x][0],dis[y][0]));
 75     return ans;
 76 }
 77 int main(){
 78     memset(dis,128,sizeof(dis));
 79     scanf("%d%d",&n,&m);
 80     for(int i=1;i<=m;i++){
 81         int u,v,w;
 82         scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w);
 83     }
 84     sort(ed+1,ed+m+1,cmp);
 85     for(int i=1;i<=n;i++){
 86         fa[i]=i;
 87     }
 88     kruskal();
 89     for(int i=1;i<=n;i++){
 90         if(!vis[i]) {
 91             dep[i]=1;
 92             dfs(i);
 93         }
 94     }
 95     for(int j=1;1<<j<=n;j++){
 96         for(int i=1;i<=n;i++){
 97             if(f[i][j-1]){
 98                 f[i][j]=f[f[i][j-1]][j-1];
 99                 dis[i][j]=min(dis[i][j-1],dis[f[i][j-1]][j-1]);
100             }
101         }
102     }
103     scanf("%d",&q);
104     for(int i=1;i<=q;i++){
105         int x,y;
106         scanf("%d%d",&x,&y);
107         if(get(x)!=get(y)){
108             printf("-1
");
109         }
110         else{
111             printf("%d
",lca(x,y));
112         }
113     }
114     return 0;
115 }
T3

day 2 T1 积木大赛

标签:CCF我抄我自己,模拟,贪心

贪心,如果还没有达到最大高度,就跟着往上加

code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 namespace gengyf{
 4 #define ll long long
 5   inline int read(){
 6     int x=0,f=1;char s=getchar();
 7     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
 8     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
 9     return f*x;
10   }
11   int n,a[1000001],sum=0;
12   int main(){
13     n=read();
14     for(int i=1;i<=n;i++){
15       a[i]=read();
16     }
17     for(int i=2;i<=n;i++){
18       if(a[i]>a[i-1])sum+=a[i]-a[i-1];
19     }
20     printf("%d",sum+a[1]);
21     return 0;
22   }
23 }
24 signed main(){
25   gengyf::main();
26   return 0;
27 }
T4

day 2 T2 花匠

标签:dp

维护两个f数组,一个表示升序,一个表示降序,分别从对方转移,答案取max

1 f[1][0]=f[1][1]=1;
2 for(int i=2;i<=n;i++){
3     if(h[i]<h[i-1])f[i][0]=f[i-1][1]+1;
4     else f[i][0]=f[i-1][0];
5     if(h[i]>h[i-1])f[i][1]=f[i-1][0]+1;
6     else f[i][1]=f[i-1][1];
7 }
转移

code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 namespace gengyf{
 4 #define ll long long
 5   inline int read(){
 6     int x=0,f=1;char s=getchar();
 7     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
 8     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
 9     return f*x;
10   }
11   const int maxn=1e5+10;
12   int h[maxn],n,f[maxn][2];
13   int main(){
14     n=read();
15     for(int i=1;i<=n;i++){
16       h[i]=read();
17     }
18     f[1][0]=f[1][1]=1;
19     for(int i=2;i<=n;i++){
20       if(h[i]<h[i-1])f[i][0]=f[i-1][1]+1;
21       else f[i][0]=f[i-1][0];
22       if(h[i]>h[i-1])f[i][1]=f[i-1][0]+1;
23       else f[i][1]=f[i-1][1];
24     }
25     printf("%d",max(f[n][0],f[n][1]));
26     return 0;
27   }
28 }
29 signed main(){
30   gengyf::main();
31   return 0;
32 }
T5

day 2 T3 华容道

标签:图论

开始看完全没思路,朴素暴搜40pts(看题解说爆搜70我懵了

这题建图简直神仙.......

我们设黑色格子为固定的"0"格子,灰色格子为可移动的"1"格子,白色格子就是空白格,红五角星为目标位置,黄五角星为指定的可移动棋子(这样例好像不太好,无解?

暴力的思路就是一步步把黄星挪到红星位置(虽然这个数据不行....

我们发现黄星可以从原来的位置移动到红星右边一格处,那么直接从黄星位置向这个位置建一条步数为边权的边

以此类推,每一个可以移动的格子都像这样建边,每次询问跑一边最短路输出就行了

不仅难想,还难写

code

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 namespace gengyf{
  4 #define ll long long
  5   inline int read(){
  6     int x=0,f=1;char s=getchar();
  7     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
  8     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
  9     return f*x;
 10   }
 11   const int inf=1e9+7;
 12   int n,m,q;
 13   int map[35][35],ans=inf,dis[35][35],qx[1010],qy[1010];
 14   int dx[5]={-1,1,0,0},dy[5]={0,0,-1,1};
 15   struct edge{
 16     int nxt,to,w;
 17   }e[40010];
 18   int head[4010],cnt,d[4010],v[4010];
 19   inline void add(int from,int to,int w){
 20     e[++cnt].to=to;e[cnt].w=w;e[cnt].nxt=head[from];head[from]=cnt;
 21   }
 22   void bfs(int sx,int sy,int bx,int by,int fx){
 23     int h=1,t=1;
 24     memset(dis,0,sizeof(dis));
 25     qx[h]=sx;qy[h]=sy;dis[sx][sy]=1;
 26     while(h<=t){
 27       int x=qx[h],y=qy[h];
 28       for(int i=0;i<4;i++){
 29         int tx=x+dx[i],ty=y+dy[i];
 30         if(map[tx][ty]&&!dis[tx][ty]&&(tx!=bx||ty!=by)){
 31           dis[tx][ty]=dis[x][y]+1;
 32           qx[++t]=tx;qy[t]=ty;
 33         }
 34       }
 35       h++;
 36     }
 37     if(fx==4)return ;
 38     for(int i=0;i<4;i++){
 39       int tx=bx+dx[i],ty=by+dy[i];
 40       if((tx!=sx||ty!=sy)&&dis[tx][ty]){
 41         add(bx*120+by*4+fx,bx*120+by*4+i,dis[tx][ty]-1);
 42       }
 43     }
 44     add(bx*120+by*4+fx,sx*120+sy*4+fx^1,1);
 45   }
 46   void spfa(int sx,int sy){
 47     queue<int>q;
 48     memset(v,0,sizeof(v));
 49     for(int i=0;i<=4010;i++){
 50       d[i]=1e7;
 51     }
 52     for(int i=0;i<4;i++){
 53       int tx=sx+dx[i],ty=sy+dy[i];
 54       if(dis[tx][ty]){
 55         d[sx*120+sy*4+i]=dis[tx][ty]-1;
 56         q.push(sx*120+sy*4+i);
 57         v[sx*120+sy*4+i]=1;
 58       }
 59     }
 60     while(q.size()){
 61       int x=q.front();q.pop();
 62       v[x]=0;
 63       for(int i=head[x];i;i=e[i].nxt){
 64         int y=e[i].to,z=e[i].w;
 65         if(d[y]>d[x]+z){
 66           d[y]=d[x]+z;
 67           if(!v[y]){
 68             v[y]=1;q.push(y);
 69           }
 70         }
 71       }
 72     }
 73   }
 74   int main(){
 75     n=read();m=read();q=read();
 76     for(int i=1;i<=n;i++)
 77       for(int j=1;j<=m;j++){
 78         map[i][j]=read();
 79       }
 80     for(int i=1;i<=n;i++)
 81       for(int j=1;j<=m;j++){
 82         if(!map[i][j])continue;
 83         if(map[i-1][j])bfs(i-1,j,i,j,0);
 84         if(map[i][j-1])bfs(i,j-1,i,j,2);
 85         if(map[i+1][j])bfs(i+1,j,i,j,1);
 86         if(map[i][j+1])bfs(i,j+1,i,j,3);
 87       }
 88     while(q--){
 89       int mx,my,sx,sy,bx,by;
 90       mx=read();my=read();sx=read();sy=read();
 91       bx=read();by=read();
 92       if(sx==bx&&sy==by){
 93         printf("0
");continue;
 94       }
 95       bfs(mx,my,sx,sy,4);
 96       spfa(sx,sy);int ans=1e7;
 97       for(int i=0;i<4;i++){
 98         ans=min(ans,d[bx*120+by*4+i]);
 99       }
100       if(ans<1e7) printf("%d
",ans);
101       else printf("-1
");
102     }
103     return 0;
104   }
105 }
106 signed main(){
107   gengyf::main();
108   return 0;
109 }
T6

原文地址:https://www.cnblogs.com/gengyf/p/11551554.html