2014noip提高组复赛解题报告

无线网络发射器选址
题目描述 Description

随着智能手机的日益普及,人们对无线网的需求日益增大。某城市决定对城市内的公共场所覆盖无线网。

假设该城市的布局为由严格平行的 129 条东西向街道和 129 条南北向街道所形成的网格状,并且相邻的平行街道之间的距离都是恒定值 1 。东西向街道从北到南依次编号为0,1,2…128,南北向街道从西到东依次编号为 0,1,2…128。

东西向街道和南北向街道相交形成路口,规定编号为 x 的南北向街道和编号为 y 的东西向街道形成的路口的坐标是(x, y)。在某些路口存在一定数量的公共场所。

由于政府财政问题,只能安装一个大型无线网络发射器。该无线网络发射器的传播范围是一个以该点为中心,边长为 2*d 的正方形。传播范围包括正方形边界。

例如下图是一个 d = 1 的无线网络发射器的覆盖范围示意图。

现在政府有关部门准备安装一个传播参数为 d 的无线网络发射器,希望你帮助他们在城 市内找出合适的安装地点,使得覆盖的公共场所最多。

输入描述 Input Description

第一行包含一个整数 d,表示无线网络发射器的传播距离。

第二行包含一个整数 n,表示有公共场所的路口数目。

接下来 n 行,每行给出三个整数 x, y, k, 中间用一个空格隔开,分别代表路口的坐标(x, y)以及该路口公共场所的数量。同一坐标只会给出一次。

 

输出描述 Output Description

输出一行,包含两个整数,用一个空格隔开,分别表示能覆盖最多公共场所的安装地点方案数,以及能覆盖的最多公共场所的数量。

样例输入 Sample Input

1

2

4 4 10

6 6 20

 

样例输出 Sample Output

1 30

数据范围及提示 Data Size & Hint

【数据范围】

对于 100%的数据,1 ≤ d ≤ 20,1 ≤ n ≤ 20, 0 ≤ x ≤ 128, 0 ≤ y ≤ 128, 0 < k ≤ 1,000,000。

题解

大模拟。。暴力枚举每个点作为所求点,然后更新最大值和次数就行了。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 int d,n,sum,ans,a[150][150];
 6 void work(int x,int y)
 7 {
 8     int ret(0);
 9     for(int i=max(1,x-d) ; i<=min(129,x+d) ; ++i)
10         for(int j=max(1,y-d) ; j<=min(129,y+d) ; ++j)
11             ret+=a[i][j];
12     if(ret>ans)
13     {
14         ans=ret;
15         sum=1;
16         return ;
17     }
18     if(ret==ans)
19     {
20         ++sum;return ;
21     } 
22 }
23 int main()
24 {
25     int x,y,k;
26     scanf("%d%d",&d,&n);
27     for(int i=1 ; i<=n ; ++i )
28     {
29         scanf("%d%d%d",&x,&y,&k);
30         a[x+1][y+1]=k;
31     }
32     for(int i=1 ; i<=129 ; ++i)
33         for(int j=1 ; j<=129 ; ++j)work(i,j);
34     printf("%d %d",sum,ans);
35     return 0;
36 }

 

寻找道路

 

题目描述 Description

在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:

1.路径上的所有点的出边所指向的点都直接或间接与终点连通。

2.在满足条件1的情况下使路径最短。

注意:图G中可能存在重边和自环,题目保证终点没有出边。

请你输出符合条件的路径的长度。

 

输入描述 Input Description

第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边。

接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。

最后一行有两个用一个空格隔开的整数s、t,表示起点为s,终点为t。

 

输出描述 Output Description

输出文件名为road.out。

输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出-1。

题解

从终点预处理出哪个点可以到达终点,然后跑spfa,拓展之前先判断是否该点所有能到达的点都能到达终点,然后就是一个裸的spfa了。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<queue>
  5 #define maxn 10005
  6 #define maxm 200005
  7 #define inf 1<<29
  8 using namespace std;
  9 int n,m,s,t,head[maxn],ecnt,vis[maxn],jud[maxn],dis[maxn],headd[maxn],cnt;
 10 struct edge{
 11     int v,nxt;
 12 }E[maxm],Ed[maxm];
 13 void add(int u,int v)
 14 {
 15     E[++ecnt].v=v;
 16     E[ecnt].nxt=head[u];
 17     head[u]=ecnt; 
 18 }
 19 void added(int u,int v)
 20 {
 21     Ed[++cnt].v=v;
 22     Ed[cnt].nxt=headd[u];
 23     headd[u]=cnt;
 24 }
 25 void bfs()
 26 {
 27     queue<int> q;
 28     memset(vis,0,sizeof(vis));
 29     vis[t]=1;
 30     q.push(t);
 31     while(!q.empty())
 32     {
 33         int d=q.front();q.pop();
 34         for(int i=headd[d] ; i ; i=Ed[i].nxt )
 35         {
 36             if(vis[Ed[i].v])continue;
 37             vis[Ed[i].v]=1;q.push(Ed[i].v);
 38         }
 39     }
 40 }
 41 void spfa()
 42 {
 43     queue<int> q;
 44     for(int i=1 ; i<=n ; ++i )dis[i]=inf;
 45     dis[s]=0;
 46     jud[s]=1;
 47     q.push(s);
 48     while(!q.empty())
 49     {
 50         int d=q.front();q.pop();jud[d]=0;
 51         int flg(0);
 52         for(int i=head[d] ; i ; i=E[i].nxt )
 53         {
 54             int v=E[i].v;
 55             if(!vis[v]){flg=1;break;}
 56         } 
 57         if(flg)continue;
 58         for(int i=head[d] ; i ; i=E[i].nxt )
 59         {
 60             int v=E[i].v;
 61             if(dis[v]>dis[d]+1)
 62             {
 63                 dis[v]=dis[d]+1;
 64                 if(!jud[v])
 65                 {
 66                     jud[v]=1;q.push(v);
 67                 }
 68             }
 69         }
 70     }
 71 }
 72 inline int read()
 73 {
 74     int ret(0);
 75     char ch=getchar();
 76     while(ch>'9'||ch<'0')ch=getchar();
 77     while(ch>='0'&&ch<='9')
 78     {
 79         ret=(ret<<1)+(ret<<3)+ch-'0';
 80         ch=getchar();
 81     }
 82     return ret;
 83 }
 84 int main()
 85 {
 86     int u,v;
 87     n=read();m=read();
 88     for(int i=1 ; i<=m ; ++i )
 89     {
 90         u=read();v=read();
 91         if(u==v)continue;
 92         add(u,v);added(v,u);
 93     }
 94     s=read();t=read();
 95     bfs();
 96     spfa();
 97     if(dis[t]==inf)printf("-1");
 98     else printf("%d",dis[t]);
 99     return 0;
100 }

 

解方程

题目描述

已知多项式方程:

a0+a1x+a2x^2+..+anx^n=0

求这个方程在[1, m ] 内的整数解(n 和m 均为正整数)

输入输出格式

输入格式:

 

输入文件名为equation .in。

输入共n + 2 行。

第一行包含2 个整数n 、m ,每两个整数之间用一个空格隔开。

接下来的n+1 行每行包含一个整数,依次为a0,a1,a2..an

 

输出格式:

 

输出文件名为equation .out 。

第一行输出方程在[1, m ] 内的整数解的个数。

接下来每行一个整数,按照从小到大的顺序依次输出方程在[1, m ] 内的一个整数解。

题解

首先30分比较好骗,直接暴力枚举就行了

满分做法比较神奇

因为没有除法运算,所以想到用模运算来简化问题,在将运算模运算处理后,考虑,如果一个数在多个模数的意义下对该式都成立,则该数为答案之一。同样的,对模数也有要求:乘积大于等于maxm,这样就避免了某个数是这所有质数的公倍数的情况。

原来模法这么神奇%%%

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int MAXN=110;
 6 int n,m,pri[10]={6529,7451,8363,9281,9829},a[5][MAXN],pre[5][MAXN],val[5][10010],cnt,ans[1000010];
 7 void read(int j)
 8 {
 9     char ch=getchar();
10     int f=1;
11     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
12     while(ch>='0'&&ch<='9')
13     {
14         for(int i=0 ; i<5 ; ++i)a[i][j]=(a[i][j]*10+ch-'0')%pri[i];
15         ch=getchar(); 
16     }
17     for(int i=0 ; i<5 ; ++i)a[i][j]*=f;
18     return ;
19 }
20 int cal(int x)
21 {
22     int ret(0);
23     for(int i=0 ; i<=n ; ++i )
24     {
25         ret=(ret+a[x][i]*pre[x][i]%pri[x])%pri[x];
26     }
27     if(ret<0)ret+=pri[x];
28     return ret;
29 }
30 bool check(int x)
31 {
32     for(int i=0 ; i<5 ; ++i )if(val[i][x%pri[i]])return false;
33     return true;
34 }
35 int main()
36 {
37     scanf("%d%d",&n,&m);
38     for(int i=0;i<=n;++i)read(i);
39     for(int i=0 ; i<5 ; ++i )
40     {
41         
42         for(int j=1 ; j<pri[i] ; ++j)
43         {
44             pre[i][0]=1;
45             for(int k=1 ; k<=n ; ++k )
46                 pre[i][k]=(pre[i][k-1]*j)%pri[i];
47             val[i][j]=cal(i);
48         }
49     }
50     for(int i=1 ; i<=m ; ++i)if(check(i))ans[++cnt]=i;
51     printf("%d\n",cnt);
52     for(int i=1 ; i<=cnt ; ++i)printf("%d\n",ans[i]);
53     return 0;
54 }

 

 

 

 

posted @ 2017-10-23 21:22 傅judge 阅读(...) 评论(...) 编辑 收藏