P8187 [USACO22FEB] Robot Instructions S

洛谷

看到 \(1\le N\le 40\) 甚至部分分 \(N\le 20\) 而且只有选和不选两种情况,这不是折半是什么?

那么直接考虑最板子的折半,前面一半从起点直接暴力搜索是否选择,得到最后的位置,另一半从终点往回走,最后统计是否有多少相等的数量即可。

但是分析一下时间复杂度,还是比较极限的,再加上如果你用 map 存储的话常数超级大,如果不卡卡常数最后可能就是压线通过的,卡常能力差一点可能会被某一些差一点的 OJ 卡。

那么考虑把 map 给优化掉。

我们直接用 vector 来存储,然后直接排序,在末尾统计时直接使用一个指针查找相同的数量,每次都只会遍历一次,时间复杂度直接优化掉了一个 \(\log\) 以及超级巨大的常数。

需要注意的是判断是否有相同的情况。

当然这道题目还可以优化,可以试着直接将几个选择数量不同的直接放在一起处理,不过整体意义也不大,所以就没有写。

下面一个是 map 的,上面一个是 vector 的,可见差距确实非常大,事实证明能不要随便用 map,当然也不排除是我的 map 写得太差了。

vector 的代码:

#include<bits/stdc++.h>
using namespace std;
int n,x[45],y[45],ex,ey,p[45];
long long ans[45];
vector<pair<int,int>> e[45],e2[45];
void dfs(int p,int z,int sum,int xx,int yy,bool f){
	if(f)e[sum].push_back({xx,yy});
	if(p>z)return;
	dfs(p+1,z,sum,xx,yy,0);
	dfs(p+1,z,sum+1,xx+x[p],yy+y[p],1);
}
void dfs2(int p,int z,int sum,int xx,int yy,bool f){
	if(f)e2[sum].push_back({xx,yy});
	if(p>z)return;
	dfs2(p+1,z,sum,xx,yy,0);
	dfs2(p+1,z,sum+1,xx-x[p],yy-y[p],1);
}
bool cmp(pair<int,int> x,pair<int,int> y){
	return x<y;
}
signed main(){
	cin>>n;
	cin>>ex>>ey;
	for(int i=1;i<=n;i++)cin>>x[i]>>y[i];
	dfs(1,(n+1)/2,0,0,0,1);
	dfs2((n+1)/2+1,n,0,ex,ey,1);
	for(int i=0;i<=(n+1)/2;i++)sort(e[i].begin(),e[i].end());
	for(int i=0;i<=(n+1)/2;i++)sort(e2[i].begin(),e2[i].end());
	for(int i=0;i<=(n+1)/2;i++){
		for(int j=0;j<=(n+1)/2;j++)p[j]=0;
		for(int o=0;o<e[i].size();o++){
			pair<int,int> k=e[i][o];
			int sum=1;
			while(o+1<e[i].size()&&e[i][o+1]==k)o++,sum++;
			for(int j=0;j<=(n+1)/2;j++){
				while(p[j]<e2[j].size()&&e2[j][p[j]]<k)p[j]++;
				while(p[j]<e2[j].size()&&e2[j][p[j]]==k)ans[j+i]+=1ll*sum,p[j]++;
			}	
		}
	}
	for(int i=1;i<=n;i++)cout<<ans[i]<<endl;
	return 0;
}

posted @ 2025-12-07 13:06  huhangqi  阅读(2)  评论(0)    收藏  举报