NOIp 2013 Day1 解题报告

NOIp 2013 Day1 解题报告

  1. 1.   转圈游戏

不难看出答案就是(x+m*10k) mod n

用快速幂算法,复杂度O(log2k)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 //variable//
 9 int n,m,x,k;
10 
11 //solve//
12 int main(){
13     scanf("%d%d%d%d",&n,&m,&k,&x);
14     int a=10,ans=1;
15     while (k){
16         if (k&1){
17             ans=(ans*a)%n;
18         }
19         k>>=1;
20         a=(a*a)%n;
21     }
22     ans=(ans*m+x)%n;
23     printf("%d\n",ans);
24     return 0;
25 }
View Code

 

  1. 2.   火柴排队

整理题设算式,我们发现,当(A1B1+A2B2+…+AnBn)最大时题设最小。

依据排序不等式,当且仅当A1<A2<…<An且B1<B2<…<Bn时上式最大。

可以看出,对于Ak和Bk,同时交换两者和仅交换其中一个是等价的,因为无论如何交换,除了Ak和Bk以外,其他A和B彼此的相对位置不变。所以,我们默认固定A,交换B中的数,使他满足上文提到的对应关系。

令A中第i个数的num[i]=i,设A中第i个数排第k,则令B中排第k的数的num[j]=i

B的num的逆序对数就是答案。

利用树状数组求逆序对,复杂度O(NlogN)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 //variable//
 9 int mod=99999997,a[110000],b[110000],st[110000],n,loc[110000],bit[110000];
10 
11 //function prototype//
12 int sumbit(int);
13 void addbit(int,int);
14 
15 //solve//
16 int main(){
17     scanf("%d",&n);
18     for (int i=1;i<=n;++i){
19         scanf("%d",a+i);
20     }
21     for (int i=1;i<=n;++i){
22         scanf("%d",b+i);
23     }
24     for (int i=1;i<=n;++i){
25         st[i]=a[i];
26     }
27     sort(st+1,st+n+1);
28     for (int i=1;i<=n;++i){
29         a[i]=lower_bound(st+1,st+n+1,a[i])-st;
30     }
31     for (int i=1;i<=n;++i){
32         st[i]=b[i];
33     }
34     sort(st+1,st+n+1);
35     for (int i=1;i<=n;++i){
36         b[i]=lower_bound(st+1,st+n+1,b[i])-st;
37     }
38     for (int i=1;i<=n;++i){
39         st[a[i]]=i;
40     }
41     for (int i=1;i<=n;++i){
42         loc[i]=st[b[i]];
43     }
44     int ans=0;
45     for (int i=n;i;--i){
46         ans=(ans+sumbit(loc[i]))%mod;
47         addbit(loc[i],1);
48     }
49     printf("%d\n",ans);
50     return 0;
51 }
52 
53 void addbit(int x,int delta){
54     for (;x<=n;x+=x&-x){
55         bit[x]+=delta;
56     }
57 }
58 
59 int sumbit(int x){
60     int ret=0;
61     for (;x;x-=x&-x){
62         ret+=bit[x];
63     }
64     return ret;
65 }
View Code

 

  1. 3.   火车运输

定理:无向带权图上,任意两点间,满足在所有路径中,路径上边权最小(大)值最大(小)的路径一定在最大(小)生成树上。

证明:依据最大(小)生成树的定义,利用反证法可以显然得证。

因此,由上可得,本题所求就是两点间路径上最小边的最大值。求出最大生成树,再在最大生成树上倍增得到每个询问的答案。

复杂度O(MlogM+NlogN+QlogN)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 using namespace std;
  7 
  8 //type//
  9 struct mingraph{
 10     int from,dest,cost,use;
 11 };
 12 
 13 //variable//
 14 mingraph g[100000];
 15 int tot=1,last[100100],prel[100100],dest[100100],cost[100100];
 16 int Q,n,m,ance[11000][20],mins[11000][20],fa[11000],vis[11000],q[11000],dep[11000];
 17 
 18 //function prototype//
 19 void kruskal(void);
 20 void addline(int,int,int);
 21 void bfs(int);
 22 void calc_ance(void);
 23 bool comp(mingraph,mingraph);
 24 int getfa(int);
 25 int calc_ans(int,int);
 26 
 27 //solve//
 28 int main(){
 29     scanf("%d%d",&n,&m);
 30     for (int i=1;i<=m;++i){
 31         scanf("%d%d%d",&g[i].from,&g[i].dest,&g[i].cost);
 32         g[i].use=0;
 33     }
 34     kruskal();
 35     for (int i=1;i<=m;++i){
 36         if (g[i].use){
 37             addline(g[i].from,g[i].dest,g[i].cost);
 38             addline(g[i].dest,g[i].from,g[i].cost);
 39         }
 40     }
 41     memset(vis,0,sizeof vis);
 42     memset(mins,0x7f,sizeof mins);
 43     for (int i=1;i<=n;++i){
 44         if (!vis[i]){
 45             bfs(i);
 46         }
 47     }
 48     calc_ance();
 49     for (scanf("%d",&Q);Q;--Q){
 50         int x,y;
 51         scanf("%d%d",&x,&y);
 52         if (getfa(x)!=getfa(y)){
 53             puts("-1");
 54         }else{
 55             printf("%d\n",calc_ans(x,y));
 56         }
 57     }
 58     return 0;
 59 }
 60 
 61 int calc_ans(int u,int v){
 62     int ans=2147000000;
 63     if (dep[u]<dep[v]){
 64         swap(u,v);
 65     }
 66     for (int j=19;j>=0;--j){
 67         if ((1<<j)&(dep[u]-dep[v])){
 68             ans=min(ans,mins[u][j]);
 69             u=ance[u][j];
 70         }
 71     }
 72     if (u==v){
 73         return ans;
 74     }
 75     for (int j=19;j>=0;--j){
 76         if (ance[u][j]!=ance[v][j]){
 77             ans=min(ans,min(mins[u][j],mins[v][j]));
 78             u=ance[u][j];
 79             v=ance[v][j];
 80         }
 81     }
 82     return min(ans,min(mins[u][0],mins[v][0]));
 83 }
 84 
 85 void calc_ance(){
 86     for (int j=1;j<20;++j){
 87         for (int i=1;i<=n;++i){
 88             ance[i][j]=ance[ance[i][j-1]][j-1];
 89             mins[i][j]=min(mins[ance[i][j-1]][j-1],mins[i][j-1]);
 90         }
 91     }
 92 }
 93 
 94 void bfs(int x){
 95     int he=1,ta=1;
 96     memset(q,0,sizeof q);
 97     q[1]=x;vis[x]=1;dep[x]=1;
 98     while (he<=ta){
 99         int u=q[he++];
100         for (int k=last[u];k;k=prel[k]){
101             if (!vis[dest[k]]){
102                 vis[dest[k]]=1;
103                 q[++ta]=dest[k];
104                 dep[dest[k]]=dep[u]+1;
105                 ance[dest[k]][0]=u;
106                 mins[dest[k]][0]=cost[k];
107             }
108         }
109     }
110 }
111 
112 void addline(int u,int v,int w){
113     dest[++tot]=v;
114     prel[tot]=last[u];
115     last[u]=tot;
116     cost[tot]=w;
117 }
118 
119 bool comp(mingraph a,mingraph b){
120     return a.cost>b.cost;
121 }
122 
123 void kruskal(){
124     sort(g+1,g+m+1,comp);
125     for (int i=1;i<=n;++i){
126         fa[i]=i;
127     }
128     int tot=0;
129     for (int i=1;i<=m;++i){
130         if (getfa(g[i].from)!=getfa(g[i].dest)){
131             g[i].use=1;
132             fa[getfa(g[i].from)]=getfa(g[i].dest);
133             ++tot;
134             if (tot==n-1){
135                 break;
136             }
137         }
138     }
139 }
140 
141 int getfa(int x){
142     return fa[x]==x? x:fa[x]=getfa(fa[x]);
143 }
View Code

 

posted @ 2015-09-13 16:18  DeAR3327  阅读(150)  评论(0编辑  收藏  举报