noip 2014 提高组 Day 2
1.无线网络发射器选址
这道题数据范围很小,就直接暴力枚举就好了。为了提高速度,就从每个有公共场所的点枚举周围在(x,y)放无线网路发射器可以增加的公共场所数量,加到一个数组里。所有公共场所都处理完了后,把这个数组扫一遍,边扫边得到最大值和个数。
其实可以用二维前缀和优化一下更快。
Code:
1 #include<iostream> 2 #include<fstream> 3 #include<map> 4 using namespace std; 5 ifstream fin("wireless.in"); 6 ofstream fout("wireless.out"); 7 typedef bool boolean; 8 typedef class Point{ 9 public: 10 int x; 11 int y; 12 Point():x(0),y(0){} 13 Point(int x,int y):x(x),y(y){} 14 boolean operator <(Point another) const{ 15 if(this->x != another.x) return this->x < another.x; 16 return this->y < another.y; 17 } 18 }Point; 19 typedef class Crossing{ 20 public: 21 Point p; 22 int count; 23 }Crossing; 24 int d,n; 25 Crossing c; 26 istream& operator >>(istream& in,Crossing& c){ 27 in>>c.p.x>>c.p.y>>c.count; 28 return in; 29 } 30 map<Point,int> counter; 31 int main(){ 32 fin>>d>>n; 33 for(int i = 1;i <= n;i++){ 34 fin>>c; 35 for(int j = c.p.x - d;j <= c.p.x + d;j++){ 36 for(int k = c.p.y - d;k <= c.p.y + d;k++){ 37 if(j < 0||k < 0) continue; 38 if(j > 128|| k > 128) break; 39 counter[Point(j,k)] += c.count; 40 } 41 } 42 } 43 int result = 0; 44 int result1 = 0; 45 for(map<Point,int>::iterator it = counter.begin();it != counter.end();it++){ 46 if(it->second > result){ 47 result = it->second; 48 result1 = 1; 49 }else if(it->second == result){ 50 result1++; 51 } 52 } 53 fout<<result1<<" "<<result; 54 return 0; 55 }
2.寻找道路
这道题貌似正着做不太好做,就构造一个反向图
反向图的话就比较清晰了,数数节点2的入度,是不是2?再看看从结束点出发能到达2的边有几条?只有1条对不对?
这就说明在原图中2的出边有一条是到不了终点的故舍去。
于是可以得到这么一个结论:路径上的点在反向图上的入度必须和结束点能到达这个点的边数相等
构造一个反图,bfs两次就能够解决
Code:
1 #include<iostream> 2 #include<fstream> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 #define LOCAL 7 #ifndef LOCAL 8 #define fin cin 9 #define fout cout 10 #endif 11 typedef bool boolean; 12 typedef class Edge { 13 public: 14 int end; 15 int next; 16 Edge():next(0),end(0){} 17 Edge(int next,int end):next(next),end(end){} 18 }Edge; 19 ifstream fin("road.in"); 20 ofstream fout("road.out"); 21 int minstance = -1; 22 int *h; 23 Edge* edge; 24 int ce; 25 int m,n; 26 int from; 27 int end; 28 int *ingoing; 29 int *findin; 30 boolean *visited; 31 void init_bfs(){ 32 queue<int> que; 33 que.push(end); 34 visited[end] = true; 35 while(!que.empty()){ 36 int e = que.front(); 37 que.pop(); 38 for(int i = h[e];i != 0;i = edge[i].next){ 39 findin[edge[i].end]++; 40 if(!visited[edge[i].end]){ 41 que.push(edge[i].end); 42 visited[edge[i].end] = true; 43 } 44 } 45 } 46 } 47 typedef class qdata{ 48 public: 49 int length; 50 int node; 51 }qdata; 52 int solve(){ 53 memset(visited, false, sizeof(boolean) * (n + 1)); 54 queue<qdata> que; 55 que.push((qdata){0,end}); 56 visited[end] = true; 57 while(!que.empty()){ 58 qdata e = que.front(); 59 que.pop(); 60 if( e.node == from ) return e.length; 61 for(int i = h[e.node];i != 0;i = edge[i].next){ 62 if(!visited[edge[i].end] && findin[edge[i].end] == ingoing[edge[i].end]){ 63 que.push((qdata){e.length + 1, edge[i].end}); 64 visited[edge[i].end] = true; 65 } 66 } 67 } 68 return -1; 69 } 70 inline void addEdge(int from,int end){ 71 edge[++ce] = Edge(h[from],end); 72 h[from] = ce; 73 ingoing[end] ++; 74 } 75 int buf[2]; 76 inline void init(){ 77 fin>>n>>m; 78 h = new int[(const int)(n + 1)]; 79 edge = new Edge[(const int)(m + 1)]; 80 ingoing = new int[(const int)(n + 1)]; 81 findin = new int[(const int)(n + 1)]; 82 visited = new boolean[(const int)(n + 1)]; 83 memset(visited, false, sizeof(boolean) * (n + 1)); 84 memset(h, 0, sizeof(int) * (n + 1)); 85 memset(ingoing, 0, sizeof(int) * (n + 1)); 86 memset(findin, 0, sizeof(int) * (n + 1)); 87 for(int i = 1;i <= m;i++){ 88 fin>>buf[0]>>buf[1]; 89 addEdge(buf[1],buf[0]); 90 } 91 fin>>from>>end; 92 } 93 int main(){ 94 init(); 95 init_bfs(); 96 fout<<solve(); 97 fin.close(); 98 fout.close(); 99 return 0; 100 }
3.解方程
这道题的数据真心恐怖,是不是有用高精度的冲动,仔细算一算:乘法时间复杂度O(N2)。貌似算几次幂TimeLimitExceeded
鉴于这里面大多数都只是乘和次方,如果说它的结果是0,那么MOD一个正整数结果还是会不变。那么就模一个较大的质数来处理,思路
就成了这样:枚举1 - m像这样计算的结果
这又面临着两个问题:
(1)TimeLimitExceeded
(2)WrongAnswer
第一个比较好理解,每个都去算,当然会超时。只是不太好解决罢了,就先说第二个
万一这个值刚好模去这个质数等于0,没事多加几个质数一起模,都是0,我才算这个是根
第二个问题解决了,现在来解决第一个问题:
比如找到了一个根m MOD p[i] = 0。 那么(m + p[i]) MOD p = 0 这么就有了一个候选值(m + p[i]),像这样就可以发现当x > p[i]的时候
再去计算结果是没有意义的,如果这个是根,它的结果会和(x - p[i])一样,所以计算答案的时候只用计算到p[i]就行了
Code:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 #define pCount 5 5 #define MAX_SIZE 20000 6 #define MAX_POW 101 7 typedef bool boolean; 8 FILE *fin = fopen("equation.in","r"); 9 FILE *fout = fopen("equation.out","w"); 10 const int p[pCount] = {16091, 13313, 10567, 16091, 19441}; 11 int a[MAX_SIZE][pCount]; 12 int factor[MAX_POW][pCount]; 13 int result[MAX_SIZE][pCount]; 14 char buf; 15 int n,m; 16 inline void seta(const int& index,const int& val){ 17 for(int i = 0;i < pCount;i++) 18 a[index][i] = val; 19 } 20 void read(int index){ 21 int f(1); 22 buf = fgetc(fin); 23 if(buf == '-') f = -1; 24 else seta(index, (int)(buf - '0')); 25 buf = fgetc(fin); 26 while(buf >= '0' && buf <= '9'){ 27 for(int i = 0;i < 5;i++){ 28 a[index][i] *= 10; 29 a[index][i] += buf - '0'; 30 a[index][i] %= p[i]; 31 } 32 buf = fgetc(fin); 33 } 34 if(f != 1){ 35 for(int i = 0;i < pCount;i++){ 36 a[index][i] *= f; 37 } 38 } 39 } 40 void cale(int x, int i){ 41 for(int j = 0;j <= n;j++){ 42 result[x][i] += factor[j][i] * a[j][i] % p[i]; 43 result[x][i] %= p[i]; 44 } 45 } 46 void init(){ 47 for(int i = 0;i < pCount;i++){ 48 result[0][i] = a[0][i]; 49 for(int j = 1;j < p[i];j++){ 50 factor[0][i] = 1; 51 for(int k = 1;k <= n;k++){ 52 factor[k][i] = factor[k - 1][i] * j % p[i]; 53 } 54 cale(j,i); 55 } 56 } 57 } 58 boolean isRoot(int x){ 59 for(int i = 0;i < pCount;i++) 60 if(result[x % p[i]][i] != 0) 61 return false; 62 return true; 63 } 64 int ans[MAX_POW]; 65 int ca = 0; 66 void solve(){ 67 for(int i = 1;i <= m;i++){ 68 if(isRoot(i)) 69 ans[ca++] = i; 70 } 71 } 72 int main(){ 73 fscanf(fin,"%d%d",&n,&m); 74 fgetc(fin); 75 for(int i = 0;i <= n;i++) 76 read(i); 77 init(); 78 solve(); 79 fprintf(fout,"%d\n",ca); 80 for(int i = 0;i < ca;i++) 81 fprintf(fout,"%d\n",ans[i]); 82 return 0; 83 }