A 无线网路发射器选址
题目描述
随着智能手机的日益普及,人们对无线网的需求日益增大。
某城市决定对城市内的公共 场所覆盖无线网。
假设该城市的布局为由严格平行的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。
n很小,最大取20,直接4个循环暴力找......
#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x) priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
int a[140][140],b[140][140],n,d;
int main()
{
while(~sc(d)){
sc(n);
met(a,0);
met(b,0);
int x,y,k;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&x,&y,&k);
a[y][x]=k;
}
int maxn=0;
int ans=0;
for(int i=0;i<=128;i++)
for(int j=0;j<=128;j++){
for(int k=i-d;k<=i+d;k++)
for(int t=j-d;t<=j+d;t++)
if(k>=0&&t>=0&&a[k][t]>0&&k<=128&&t<=128)
b[i][j]+=a[k][t];
if(maxn<b[i][j]){
maxn=b[i][j];
}
}
for(int i=0;i<=128;i++)
for(int j=0;j<=128;j++)
if(b[i][j]==maxn)
ans++;
printf("%d %d\n",ans,maxn);
}
}
B 车站分级
题目描述
一条单向的铁路线上,依次有编号为 1, 2, …, n 的 n 个火车站。
每个火车站都有一个级 别,最低为 1 级。
现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车 次停靠了火车站 x,则始发站、终点站之间所有级别大于等于火车站 x 的都必须停靠。
(注 意:起始站和终点站自然也算作事先已知需要停靠的站点)
例如,下表是 5 趟车次的运行情况。
其中,前 4 趟车次均满足要求,而第 5 趟车次由于 停靠了 3 号火车站(2 级)却未停靠途经的 6 号火车站(亦为 2 级)而不满足要求。
现有 m 趟车次的运行情况(全部满足要求),试推算这 n 个火车站至少分为几个不同的 级别。
输入
第一行包含 2 个正整数 n, m,用一个空格隔开。
第 i + 1 行(1 ≤ i ≤ m)中,首先是一个正整数 si(2 ≤ si ≤ n),表示第 i 趟车次有 si 个停 靠站;
接下来有 si个正整数,表示所有停靠站的编号,从小到大排列。
每两个数之间用一个 空格隔开。输入保证所有的车次都满足要求。
输出
输出只有一行,包含一个正整数,即 n 个火车站最少划分的级别数。
样例输入
9 2
4 1 3 5 6
3 3 5 6
样例输出
2
提示
【数据范围】
对于 20%的数据,1 ≤ n, m ≤ 10;
对于 50%的数据,1 ≤ n, m ≤ 100;
对于 100%的数据,1 ≤ n, m ≤ 1000。
这个题题意大概是有m趟车次,每次从起始站到终点站这条路上停靠的站一定比不停靠的站级别高,问最少可以将这些车站划分为几个级别?
读完题可以得出停的站一定比没有停的站级别高,由此我们想到了拓扑排序,把级别从低到高的车站排序递推一下就好了。而问题的关键是怎样建图,
这里我是用vector建的,将这趟车次没有停靠的点和停靠过的点连接起来。
#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x) priority_queue<x>
#define ull unsigned long long
#define scn(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N = 1100;
int ru[N],edge[N][N],vis[N],pd[N][N],ans,n,m;
vector<int>e[N];
queue<pair<int,int> >q;
void tuopu()
{
for(int i=1;i<=n;i++)
if(ru[i]==0)
q.push(make_pair(i,1)); //加入编号为i,级别为1的车站
ans=1; //初始化级别为1
while(!q.empty())
{
int u=q.front().first; //车站的编号
int w=q.front().second; //级别
q.pop();
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i];
ru[v]--;
if(ru[v]==0)
{
q.push(make_pair(v,w+1));
ans=max(ans,w+1); //递推
}
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
met(pd,0);
met(edge,0);
met(ru,0);
for(int i=1;i<=m;i++)
{
met(vis,false);
scanf("%d",&edge[i][0]); //用edge[i][0]存停靠车站的个数
for(int j=1;j<=edge[i][0];j++)
{
scanf("%d",&edge[i][j]);
vis[edge[i][j]]=1; //vis数组表示是否停靠过
}
for(int k=edge[i][1];k<=edge[i][edge[i][0]];k++)
{
if(vis[k]) //如果停靠了,略过只找没停过的车站
continue;
for(int l=1;l<=edge[i][0];l++) //依次遍历所有停靠过的车站
{
if(!pd[k][edge[i][l]]) //判断是否连接,没有就连上
{
e[k].push_back(edge[i][l]); //加边
ru[edge[i][l]]++; //入度+1
pd[k][edge[i][l]]=1;
}
}
}
}
tuopu();
printf("%d\n",ans);
}
}
D 小朋友的数字(dp)
题目描述
有 n 个小朋友排成一列。每个小朋友手上都有一个数字,这个数字可正可负。
规定每个 小朋友的特征值等于排在他前面(包括他本人)的小朋友中连续若干个(最少有一个)小朋 友手上的数字之和的最大值。
作为这些小朋友的老师,你需要给每个小朋友一个分数,分数是这样规定的:第一个小 朋友的分数是他的特征值,其它小朋友的分数为排在他前面的所有小朋友中(不包括他本人), 小朋友分数加上其特征值的最大值。
请计算所有小朋友分数的最大值,输出时保持最大值的符号,将其绝对值对 p 取模后 输出。
输入
第一行包含两个正整数 n、p,之间用一个空格隔开。
第二行包含 n 个数,每两个整数之间用一个空格隔开,表示每个小朋友手上的数字。
输出
输出只有一行,包含一个整数,表示最大分数对 p 取模的结果。
样例输入
5 997
1 2 3 4 5
样例输出
21
提示
小朋友的特征值分别为 1、3、6、10、15,分数分别为 1、2、5、11、21,最大值 21 对 997 的模是 21。
【数据范围】
对于 50%的数据,1 ≤ n ≤ 1,000,1 ≤ p ≤ 1,000所有数字的绝对值不超过 1000;
对于 100%的数据,1 ≤ n ≤ 1,000,000,1 ≤ p ≤ 1e9,其他数字的绝对值均不超过 1e9。
之前的题解有点问题。。又理解了好长时间orz...然后取模还是有点不理解(比赛时就取上了模。。)
这个就是先用最大连续子序列和先求特征值,然后求分数就好了,只要找特征值大于0的就可以,因为最后答案肯定是第一个或者最后一个,具体看代码
#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x) priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N=1e6+10;
ll n,a[N],p,b[N],dp[N],f[N];
int main()
{
while(~scanf("%lld%lld",&n,&p)){
bool flag;
ll maxn=-1e9-10;
ll x=0;
met(b,0);
met(a,0);
met(dp,0);
met(f,0);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
dp[1]=a[1];
f[1]=a[1];
maxn=a[1];
for(int i=2;i<=n;i++){ //最大连续子序列和
dp[i]=max(dp[i-1]+a[i],a[i]);
f[i]=max(maxn,dp[i]);
maxn=f[i];
}
b[1]=f[1];
b[2]=2*f[1]; //第二个人的分数就是第一个人的特征值的两倍
flag=true;
if(b[2]>b[1])
flag=false; //如果大于第一个人的分数就把标记写成false
for(int i=3;i<=n;i++){
if(f[i-1]>0){
b[i]=b[i-1]+f[i-1];
if(b[i]>b[1]) //如果大于第一个人的分数就把标记写成false
flag=false;
if(b[i]>1e9) //这里要取模,还是解释不了...orz,可能正好大一倍?
b[i]%=p;
}
else b[i]=b[2];
}
if(flag==false)
printf("%lld\n",b[n]%p);
else printf("%lld\n",b[1]); //如果最后是true,就说明第一个人的分数是最大的
}
}