P12022 [USACO25OPEN CU] Hoof Paper Scissors Minus One

题意简述

给定各个手势之间的胜负关系,求在对方出两个手势时出至少一个可以同时至少打平这两个手势的方案数。

解题思路

令可以打败或打平某个手势的手势为其“上级手势”,则我们考虑存储每个手势对应的若干个“上级手势”,预先排序,随后在询问时遍历每个手势,二分查找判断出当前手势是否可以同时打败给出的两个手势。统计答案时容易发现只要使用了满足上述要求的手势就能确保获胜,所以另一个手势是任意的,对于每个满足要求的手势都有 \(2\times N-1\) 种搭配方案(同个手势出两个只会产生一种方案),直接做乘法统计。

但我们又注意到如果两个手势 \(i\)\(j\) 都是满足条件的,那么计算答案时会把 \(i,j\)\(j,i\) 都给统计两遍,所以要再扣除这种情况。然后就可以通过本题。

参考代码

#include<bits/stdc++.h>
#define int long long
//很重要!!!
#define pb push_back
using namespace std;
int n,m; 
const int N=3005; 
char opt[N][N];
vector<int>w[N],ans;  
signed main() {
	cin.tie(0)->sync_with_stdio(0);cout.tie(0);
	cin>>n>>m; 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			cin>>opt[i][j]; 
			if(opt[i][j]=='L')w[i].pb(j); 
			else if(opt[i][j]=='W')w[j].pb(i);     
		}
	}
	for(int i=1;i<=n;i++)sort(w[i].begin(),w[i].end()); //排序 
	while(m--){
		int s1,s2;cin>>s1>>s2; 
		for(int i=1;i<=n;i++){
			if(binary_search(w[s1].begin(),w[s1].end(),i)&&binary_search(w[s2].begin(),w[s2].end(),i)) ans.pb(i); 
			//二分查找判断手势是否满足条件  
		}
		if(!ans.size()) {
			cout<<0<<'\n'; continue; 
			//没有手势满足条件 
		}
		int tmp=ans.size();//满足条件手势个数 
		int sum=tmp+tmp*(n-1)*2;//第一遍乘法    
		sum-=tmp*(tmp-1);//扣除多次计算的部分 
		cout<<sum<<'\n';
		ans.clear();//多测要清空  
	}
	return 0;
}

posted @ 2025-05-03 23:46  Tiger_Rory  阅读(22)  评论(0)    收藏  举报
//雪花飘落效果