ABC160D - Line++ 题解
题意:给出 \(N,X,Y\)。有 \(N\) 条无向边:
- 对于 \(i=1,2,\cdots,N-1\),连一条从点 \(i\) 到点 \(i+1\) 的无向边。
- 连一条从点 \(X\) 到点 \(Y\) 的无向边。
对于 \(k=1,2,\cdots,N-1\),要求解决以下问题:
- 找到能使无向边 \((i,j)(1\le i<j\le N)\) 的距离为 \(k\) 的方案数。
数据范围:
- \(3\le N\le 2\times 10^3\)
- \(1\le X,Y\le N\)
- \(X+1<Y\)
————————————————————————————————————————————————
Sol:
显然,使用 \(O(N^3)\) 的 Floyd 算法是不可行的,会直接 TLE。
我们分析一下题目后,会发现:题目中的这个无向图,假如去掉 \((X,Y)\) 这条无向边之后,便会成为一条链!
事实上,\(O(N^3)\) 的 Floyd 算法是一种解决图的多源最短路径的预处理方法。在本题这种情况下,显然有些大材小用了。
我们是否可以找到一种时间复杂度为 \(O(N^2)\) 的预处理方法呢?答案是肯定的。
设 \(s(i,j)\) 为点 \(i\) 到点 \(j\) 的最短距离。那么枚举 \(i,j(1\le i<N,i<j\le N)\),则 \(s(i,j)=\min\{j-i,|X-i|+|Y-j|\}\)。
其中,\(j-i\) 为不可以经过 \((X,Y)\) 的 \(i\) 到 \(j\) 的最短距离,\(|X-i|+|Y-j|\) 为必须经过 \((X,Y)\) 的 \(i\) 到 \(j\) 的最短距离。
再使用一个桶 \(T()\)。枚举 \(i,j(1\le i<N,i<j\le N)\),每次枚举到一组 \(i\) 和 \(j\) 后,\(T(s(i,j))\gets T(s(i,j))+1\)。
最终,枚举 \(k=1,2,\cdots,N-1\),每次输出 \(T(k)\) 即为最终答案。
————————————————————————————————————————————————
Code:
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define iterator IT
#define SIZ(V) V.size()
#define FS(a) fixed<<setprecision(a)
using namespace std;
namespace STARTER {
int MAX(int a,int b) {return a>b?a:b;}
int MIN(int a,int b) {return a<b?a:b;}
int ABS(int a) {return a<0?-a:a;}
int GCD(int a,int b) {return !b?a:GCD(b,a%b);}
int LCM(int a,int b) {return a/GCD(a,b)*b;}
int QSM(int a,int b,int p) {int ret=1;while (b) (b&1)&&(ret=ret*a%p),a=a*a%p,b>>=1;return ret;}
int ROUND(double a) {return a+0.5;}
}
using STARTER::MAX;
using STARTER::MIN;
using STARTER::ABS;
using STARTER::GCD;
using STARTER::LCM;
using STARTER::QSM;
using STARTER::ROUND;
const int maxN=2005;int n,x,y,/*dis[maxN][maxN],*/s[maxN][maxN],ans[maxN],t[maxN*maxN];
int main() {
cin>>n>>x>>y/*,dis[x][y]=1*/;
//for (int i=1;i<n;i++) dis[i][i+1]=1;
//for (int i=1;i<n;i++)
// for (int j=i+1;j<=n;j++) dis[i][j]=1;
for (int i=1;i<n;i++)
for (int j=i+1;j<=n;j++) //{
//if (i<=x&&j>=y) s[i][j]=x-i+1+j-y;
//else s[i][j]=j-i;
s[i][j]=min(j-i,ABS(x-i)+1+ABS(y-j));
//}
//for (int i=1;i<n;i++) {
// for (int j=i+1;j<=n;j++) printf("s[%d][%d]=%d ",i,j,s[i][j]);
// puts("");
//}
for (int i=1;i<n;i++)
for (int j=i+1;j<=n;j++) t[s[i][j]]++;
for (int k=1;k<n;k++) cout<<t[k]<<'\n';
}
转载是允许的,但是除了博主同意的情况下,必须在文章的明显区域说明出处,否则将会追究其法律责任。