2014noip提高组复赛解题报告
随着智能手机的日益普及,人们对无线网的需求日益增大。某城市决定对城市内的公共场所覆盖无线网。
假设该城市的布局为由严格平行的 129 条东西向街道和 129 条南北向街道所形成的网格状,并且相邻的平行街道之间的距离都是恒定值 1 。东西向街道从北到南依次编号为0,1,2…128,南北向街道从西到东依次编号为 0,1,2…128。
东西向街道和南北向街道相交形成路口,规定编号为 x 的南北向街道和编号为 y 的东西向街道形成的路口的坐标是(x, y)。在某些路口存在一定数量的公共场所。
由于政府财政问题,只能安装一个大型无线网络发射器。该无线网络发射器的传播范围是一个以该点为中心,边长为 2*d 的正方形。传播范围包括正方形边界。
例如下图是一个 d = 1 的无线网络发射器的覆盖范围示意图。
现在政府有关部门准备安装一个传播参数为 d 的无线网络发射器,希望你帮助他们在城 市内找出合适的安装地点,使得覆盖的公共场所最多。
第一行包含一个整数 d,表示无线网络发射器的传播距离。
第二行包含一个整数 n,表示有公共场所的路口数目。
接下来 n 行,每行给出三个整数 x, y, k, 中间用一个空格隔开,分别代表路口的坐标(x, y)以及该路口公共场所的数量。同一坐标只会给出一次。
输出一行,包含两个整数,用一个空格隔开,分别表示能覆盖最多公共场所的安装地点方案数,以及能覆盖的最多公共场所的数量。
1
2
4 4 10
6 6 20
1 30
【数据范围】
对于 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 }
寻找道路
在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1.路径上的所有点的出边所指向的点都直接或间接与终点连通。
2.在满足条件1的情况下使路径最短。
注意:图G中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边。
接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。
最后一行有两个用一个空格隔开的整数s、t,表示起点为s,终点为t。
输出文件名为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 }