[题解]noip提高组

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 }
时间: 2024-10-25 04:18:31

[题解]noip提高组的相关文章

NOIP提高组2004 合并果子题解

NOIP提高组2004 合并果子题解 描述:在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和.可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了.多多在合并果子时总共消耗的体力等于每次合并所耗体力之和. 因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力.假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出

NOIP提高组 1999 &amp; 2000 题解合集

[序言]话说我在学神奇算法的时候,基础应该也要巩固,于是打算提前把NOIP提高组的刷完. 具体的题目描述和提交我就在VIJOS上完成. [1999.1] 描述 给定一个信封,最多只允许粘贴N张邮票,计算在给定M(N+M<=10)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大max ,使得1-max之间的每一个邮资值都能得到. 例如,N=3,M=2,如果面值分别为1分.4分,则在l分-6分之间的每一个邮资值都能得到(当然还有8分.9分和12分):如果面值分别为1分.3分

2017.12.02【NOIP提高组】模拟赛A组

2017.12.02[NOIP提高组]模拟赛A组 T1 3555[GDKOI2014模拟]树的直径 T2 3542[清华集训2014]冒泡排序 T3 3486[NOIP2013模拟联考10]道路改建(rebuild) T1 树直径的一个性质,两棵树合并,形成新的树的直径的两个端点为原树中的四个端点之二. 可以用反证法证明.用此性质本题就变成了lca裸题了 Code #include<cstdio> #include<cstring> #include<cmath> #i

Vijos P1002 过河 (NOIP提高组2005)

链接:https://www.vijos.org/p/1002 解析: 若 p*x+(p+1)*y=Q(采用跳跃距离p和p+1时可以跳至任何位置Q),则在Q ≥ P*(P-1)时是一定有解的. 由于题目给出的一个区间是1≤S≤T≤10,于是当相邻的两个石子之间的距离不小于8*9=72时,则后面的距离都可以到达,我们就可以认为它们之间的距离就是72.如此一来,我们就将原题L的范围缩小为了100*72=7200,动态规划算法完全可以承受了. 但是当S=T时,上述等式是无法使用的,在这种情况下,只需要

NOIP 提高组2013 火柴排队 (Vijos P1842)

描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度.现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:∑ i=1 n (a i ?b i ) 2  ,其中 a i   表示第一列火柴中第 i 个火柴的高度,b i   表示第二列火柴中第 i 个火柴的高度. 每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小.请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模

2017.11.25【NOIP提高组】模拟赛A组

2017.11.25[NOIP提高组]模拟赛A组 T1 3467. [NOIP2013模拟联考7]最长上升子序列(lis) T2 3468. [NOIP2013模拟联考7]OSU!(osu) T3 3472. [NOIP2013模拟联考8]匹配(match) T1 有转移方程f[i]=max{f[j]}+1,a[j]<a[i] 可以用线段树+离散化维护这个方程,因为涉及以往状态可以用主席树维护 打太丑爆空间了 Code 1 #include<cstdio> 2 #include<c

2017.12.09【NOIP提高组】模拟赛A组

2017.12.09[NOIP提高组]模拟赛A组 T1 3489. [NOIP2013模拟联考11]数列的GCD(gcd) T2 3500.[NOIP2013模拟联考15]物语(monogatari) T3 3501.[NOIP2013模拟联考15]消息传递(news) 吐槽:这次的题好像有点水啊,但最简单的第二题都给打挂啦!!(数组开小了) T1 本套题中最难的题.考虑dp 设f[i]是b[1],b[2]...b[N]的最大公约数的数目,g[i]是b[1],b[2]...b[N]的公约数的数目

2015 Noip提高组 Day1

P2615 神奇的幻方 [题目描述] 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最

NOIP提高组 2009 靶形数独 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 此题解目前在洛谷上无法AC,只能拿到95分,使用洛谷的朋友请注意. 题目链接:  洛谷   CODEVS  Vijos 描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z博士请教, Z 博士拿出了他最近发明的“靶形数独” ,作为这两个孩子比试的题目. 靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有 9