2014Noip提高组复赛Day2题解

无线网络发射器选址

题目描述 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。

 思路: 枚举就行了,注意要从(0,0)开始

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int x[500],y[500],k[500],mp[500][500],pre[500][500],d,n,ans,cnt;
inline int read()
{
    int x=0;int f=1;
    char ch;
    ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();
     } 
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
int main()
{
    d=read();n=read();
    for(int i=1;i<=n;++i)
    {
        x[i]=read();y[i]=read();k[i]=read();
        mp[x[i]+50][y[i]+50]=k[i];
    } 
    pre[50][50]=mp[50][50];
    for(int i=50;i<=228+50;++i) pre[i][50]=pre[i-1][50]+mp[i][50];
    for(int j=50;j<=228+50;++j) pre[50][j]=pre[50][j-1]+mp[50][j];
    for(int i=51;i<=228+50;++i)
    {
        for(int j=51;j<=228+50;++j)
        {
            pre[i][j]=pre[i][j-1]+pre[i-1][j]-pre[i-1][j-1]+mp[i][j];
        }
    }
    for(int i=50;i<=128+50;++i)
    {
        for(int j=50;j<=128+50;++j)
        {
            int tot=0;
            tot=pre[i+d][j+d]-pre[i+d][j-d-1]-pre[i-d-1][j+d]+pre[i-d-1][j-d-1];
            if(tot==ans) ++cnt;
            else if(tot>ans) cnt=1,ans=tot;
        }
    }
    printf("%d %d\n",cnt,ans);
    return 0;
    
}

寻找道路

题目描述 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。

样例输入 Sample Input

road.in

road.out

3 2

1 2

2 1

1 3

-1

样例输出 Sample Output

road.in

road.out

6 6

1 2

1 3

2 6

2 5

4 5

3 4

1 5

3

数据范围及提示 Data Size & Hint

对于30%的数据,0< n ≤10,0< m ≤20;

对于60%的数据,0< n ≤100,0< m ≤2000;

对于100%的数据,0< n ≤10,000,0< m ≤200,000,0< x,y,s,t≤n,x≠t。

 思路:要建反图,然后从终点开始跑bfs,判断每一条边是否能到达终点,若是不能则对边做标记,然后再从起点跑一遍dfs,边的起点被标记不能走的就不对其进行深搜,最后跑一遍spfa

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<queue>
  5 #define maxn 10010
  6 #define maxm 200010
  7 using namespace std;
  8 int head1[maxn],head2[maxn],ecnt1,ecnt2,dis[maxn],vis[maxn],s,t,n,m,can[maxn];
  9 const int inf=0x3f3f3f3f;
 10 inline int read()
 11 {
 12     int x=0;int f=1;
 13     char ch=getchar();
 14     while(ch<'0'||ch>'9')
 15     {
 16         if(ch=='-') f=-1;
 17         ch=getchar();
 18     } 
 19     while(ch>='0'&&ch<='9')
 20     {
 21         x=x*10+ch-'0';
 22         ch=getchar();
 23     }
 24     return x*f;
 25 }
 26 struct edge1
 27 {
 28     int u,v,w,can,next;
 29 }E1[maxm],E2[maxm];
 30 void add1(int u,int v)
 31 {
 32     E1[++ecnt1].u=u;
 33     E1[ecnt1].v=v;
 34     E1[ecnt1].w=1;
 35     E1[ecnt1].next=head1[u];
 36     head1[u]=ecnt1;
 37 }
 38 void add2(int u,int v)
 39 {
 40     E2[++ecnt2].u=u;
 41     E2[ecnt2].v=v;
 42     E2[ecnt2].w=1;
 43     E2[ecnt2].next=head2[u];
 44     head2[u]=ecnt2;
 45 }
 46 void bfs()
 47 {
 48     queue<int>q;
 49     vis[t]=1;
 50     q.push(t);
 51     while(!q.empty())
 52     {
 53         int u=q.front();
 54         q.pop();
 55         for(int i=head2[u];i;i=E2[i].next)
 56         {
 57             int v=E2[i].v;
 58             E1[i].can=1;
 59             if(!vis[v])
 60             {
 61                 vis[v]=1;
 62                 q.push(v);
 63             } 
 64         }
 65     }
 66 }
 67 void dfs(int x)
 68 {
 69     vis[x]=1;
 70     bool flg=1;
 71     for(int i=head1[x];i;i=E1[i].next)
 72     {
 73         int v=E1[i].v;
 74         flg&=E1[i].can;
 75         if(!vis[v]) dfs(v);
 76     }
 77     can[x]=flg;
 78 }
 79 void spfa()
 80 {
 81     queue<int>q;
 82     q.push(s);
 83     dis[s]=0;
 84     vis[s]=1;
 85     while(!q.empty())
 86     {
 87         int u=q.front();
 88         for(int i=head1[u];i;i=E1[i].next)
 89         {
 90             int v=E1[i].v;
 91             if(!can[v]) continue;
 92             if(dis[v]>dis[u]+E1[i].w)
 93             {
 94                 dis[v]=dis[u]+E1[i].w;
 95                 q.push(v);
 96                 vis[v]=1;
 97             }
 98         }
 99         q.pop();
100         vis[u]=0;
101      } 
102 }
103 int main()
104 {
105     n=read();m=read();
106     for(int i=1;i<=m;++i)
107     {
108         int a,b;
109         a=read();b=read();
110         add1(a,b);
111         add2(b,a);
112     }
113     s=read();
114     t=read();
115     bfs();
116     memset(vis,0,sizeof(vis));
117     dfs(s);
118     if(!can[s])
119     {
120         puts("-1");
121         return 0;
122     }
123     memset(vis,0,sizeof(vis));
124     memset(dis,inf,sizeof(dis));
125     spfa();
126     printf("%d\n",dis[t]);
127     return 0;
128  } 

 解方程

题目描述 Description

输入描述 Input Description

输入文件名为equation.in。

输入共n+2行。

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

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

 

输出描述 Output Description

输出文件名为equation.out。

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

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

 

 

样例输入 Sample Input

equation.in

equation.out

2 10

1

-2

1

 

1

1

equation.in

equation.out

2 10

-3

1

 

2

1

2

 

样例输出 Sample Output

equation.in

equation.out

2 10

1

3

2

 

0

数据范围及提示 Data Size & Hint

思路:找一堆质数然后取模,枚举,质数越多就越能保证正确率(其实就是靠玄学。。)

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

 

posted @ 2017-10-24 08:41  mljkw_gsry  阅读(491)  评论(1编辑  收藏  举报