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';
}
posted @ 2020-03-28 23:09  Aehnuwx  阅读(155)  评论(0编辑  收藏  举报