1. 程式人生 > 其它 >【題解】2021.9.11 - zhengru IOI 七連測 Day3

【題解】2021.9.11 - zhengru IOI 七連測 Day3

\(\color{Red}{How-great-the-day-is-!(Wrong)}\)

T1 斯諾克

思路

程式碼

T2 翻轉

思路

程式碼

T3 數對

思路

  • 對於每一個 \(a_i\)\(b_j\) ,當且僅當 \(a_i \oplus 2^x=b_j \oplus 2^y\)\(x ≠ y\)

  • 於是,只需要對於每一個 \(a_i\) 算出 \(a_i \oplus 2^x\) 的值,然後找與其相等的 \(b_j\) 的值即可。

  • 需要注意的是,當 \(a_i=b_j\) 時,對於每個次冪都會統計一次答案,減去即可。

  • 另外,因為判斷的只是相等,所以對於每個數對有兩種異或方式,答案要除以二。

程式碼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<utility>
#include<deque>
#include<ctime> 
#include<sstream>
#include<list>
#include<bitset> 
using namespace std; 
int na[100233],nb[100233],cna,cnb,n,m;
map<int,int> sam;
long long ans,pa[3000233],pb[3000233];
int main(){
	scanf("%d%d",&n,&m);
	for(register int i=1;i<=n;++i){
		scanf("%d",&na[i]);
		sam[na[i]]++;
		for(register int j=0;j<30;++j){
			pa[++cna]=na[i]^(1<<j);
		}
	}
	for(register int i=1;i<=m;++i){
		scanf("%d",&nb[i]);
		ans-=sam[nb[i]]*30;
		for(register int j=0;j<30;++j){
			pb[++cnb]=nb[i]^(1<<j);
		}
	}
	sort(pa+1,pa+cna+1);sort(pb+1,pb+cnb+1);
	for(register int i=1,l=1,r=1;i<=cna;++i){
		while(pb[l]<pa[i]&&l<=cnb) ++l;
		while(pb[r]<=pa[i]&&r<=cnb) ++r;
		if(pa[i]==pb[l]) ans+=(r-l);
	}
	printf("%lld\n",ans>>1);
	return 0;
}

T4 迴文串

思路

程式碼