2019.10.15模拟赛总结

T1:数独

题意:有 5 5 5种操作,分别为插入,删除,查询,合并,输出。
2019.10.15模拟赛总结_第1张图片
2019.10.15模拟赛总结_第2张图片
2019.10.15模拟赛总结_第3张图片
2019.10.15模拟赛总结_第4张图片
解析:一道模拟题,注意细节就好了。

#include
using namespace std;
int Read(){
	int x=0;
	char ch=getchar();
	while(!isdigit(ch)){
		ch=getchar();
	}
	while(isdigit(ch)){
		x=(x<<3)+(x<<1)+ch-'0';
		ch=getchar();
	}
	return x;
}
const int mp[10][10]={{0,0,0,0,0,0,0,0,0,0},
					  {0,1,1,1,2,2,2,3,3,3},
					  {0,1,1,1,2,2,2,3,3,3},
					  {0,1,1,1,2,2,2,3,3,3},
					  {0,4,4,4,5,5,5,6,6,6},
					  {0,4,4,4,5,5,5,6,6,6},
					  {0,4,4,4,5,5,5,6,6,6},
					  {0,7,7,7,8,8,8,9,9,9},
					  {0,7,7,7,8,8,8,9,9,9},
					  {0,7,7,7,8,8,8,9,9,9}};
struct Node{
	int h[10],l[10],g[10];
	int a[10][10];
	void Clear(){
		for(int i=1;i<=9;i++){
			h[i]=l[i]=g[i]=0;
			for(int j=1;j<=9;j++){
				a[i][j]=0;
			}
		}
	}
}f[105];
int cnt=0;
char s[105];
bool pd(int k,int x,int y,int i){
	return (!(f[k].h[x]&(1<<i)))&&!((f[k].l[y]&(1<<i)))&&(!(f[k].g[mp[x][y]]&(1<<i)));
}
void Copy(){
	++cnt;
	for(int i=1;i<=9;i++){
		f[cnt].h[i]=f[cnt-1].h[i];
		f[cnt].l[i]=f[cnt-1].l[i];
		f[cnt].g[i]=f[cnt-1].g[i];
		for(int j=1;j<=9;j++){
			f[cnt].a[i][j]=f[cnt-1].a[i][j];
		}
	}
}
void Re(){
	for(int i=1;i<=9;i++){
		f[cnt].h[i]=f[cnt].g[i]=f[cnt].l[i]=0;
	}
	for(int i=1;i<=9;i++){
		for(int j=1;j<=9;j++){
			f[cnt].h[i]|=(1<<f[cnt].a[i][j]);
			f[cnt].l[j]|=(1<<f[cnt].a[i][j]);
			f[cnt].g[mp[i][j]]|=(1<<f[cnt].a[i][j]);
		}
	}
}
void Ins(int x,int y,int k){
	Copy();
	if(f[cnt].a[x][y]){
		printf("Error\n");
		return ;
	}
	if(f[cnt].h[x]&(1<<k)){
		printf("Error:row!\n");
		return ;
	}
	if(f[cnt].l[y]&(1<<k)){
		printf("Error:column!\n");
		return ;
	}
	if(f[cnt].g[mp[x][y]]&(1<<k)){
		printf("Error:square!\n");
		return ;
	}
	printf("OK!\n");
	f[cnt].h[x]|=(1<<k);
	f[cnt].l[y]|=(1<<k);
	f[cnt].g[mp[x][y]]|=(1<<k);
	f[cnt].a[x][y]=k;
}
void Del(int x,int y){
	Copy();
	if(f[cnt].a[x][y]==0){
		printf("Error!\n");
		return ;
	}
	printf("OK!\n");
	f[cnt].a[x][y]=0;
	Re();
}
void query(int x,int y){
	Copy();
	if(f[cnt].a[x][y]){
		printf("Error!\n");
		return ;
	}
	int ans=0,Q[105];
	for(int i=1;i<=9;i++){
		if(pd(cnt,x,y,i))  Q[++ans]=i;
	}
	cout<<ans<<endl;
	for(int i=1;i<=ans;i++){
		printf("%d\n",Q[i]);
	}
}
void Merge(int x,int y){
	int ans1=0,ans2=0;
	Copy();
	f[cnt].Clear();
	for(int i=1;i<=9;i++){
		for(int j=1;j<=9;j++){
			if(f[x].a[i][j]){
				if(pd(cnt,i,j,f[x].a[i][j])){
					f[cnt].a[i][j]=f[x].a[i][j];
					f[cnt].h[i]|=(1<<f[x].a[i][j]);
					f[cnt].l[j]|=(1<<f[x].a[i][j]);
					f[cnt].g[mp[i][j]]|=(1<<f[x].a[i][j]);
					ans1++;
					continue;
				}
			}
			if(f[y].a[i][j]){
				if(pd(cnt,i,j,f[y].a[i][j])){
					f[cnt].a[i][j]=f[y].a[i][j];
					f[cnt].h[i]|=(1<<f[y].a[i][j]);
					f[cnt].l[j]|=(1<<f[y].a[i][j]);
					f[cnt].g[mp[i][j]]|=(1<<f[y].a[i][j]);
					ans2++;
				}
			}
		}
	}
	printf("%d %d\n",ans1,ans2);
}
void Print(){
	Copy();
	for(int i=1;i<=9;i++){
		printf("+-+-+-+-+-+-+-+-+-+\n");
		for(int j=1;j<=9;j++){
			printf("|%d",f[cnt].a[i][j]);
		}
		printf("|\n");
	}
	printf("+-+-+-+-+-+-+-+-+-+\n");
}
int main(){
	freopen("sudoku.in","r",stdin);
	freopen("sudoku.out","w",stdout);
	for(int i=1;i<=9;i++){
		for(int j=1;j<=9;j++){
			f[0].a[i][j]=Read();
			f[0].h[i]|=(1<<f[0].a[i][j]);
			f[0].l[j]|=(1<<f[0].a[i][j]);
			f[0].g[mp[i][j]]|=(1<<f[0].a[i][j]);
		}
	}
	int T=Read(),x,y,k;
	while(T--){
		scanf("%s",s);
		if(s[0]=='I'){
			x=Read(),y=Read(),k=Read();
			Ins(x,y,k);
		}
		if(s[0]=='D'){
			x=Read(),y=Read();
			Del(x,y);
		}
		if(s[0]=='Q'){
			x=Read(),y=Read();
			query(x,y);
		}
		if(s[0]=='M'){
			x=Read(),y=Read();
			Merge(x,y);
		}
		if(s[0]=='P'){
			Print();
		}
	}
	fclose(stdin);
	fclose(stdout);
}

没什么好说的,注意读题!!!

T2:分糖果(原皇后游戏)

传送门

解析:题目要求的是这样一个式子中 c [ i ] c[i] c[i]的最大值的最小值:
2019.10.15模拟赛总结_第5张图片
由于 a i , b i a_i,b_i ai,bi均为正数,所以 c i c_i ci一定是递增的,故我们要求的即为 c n c_n cn的最小值。

我们有一个结论:对于两位大臣 ( a i , b i ) , ( a j , b j ) (a_i,b_i),(a_j,b_j) (ai,bi),(aj,bj),如果 m i n ( a i , b j ) ≤ m i n ( a j , b i ) min(a_i,b_j)\le min(a_j,b_i) min(ai,bj)min(aj,bi),那么我们将 ( a i , b i ) (a_i,b_i) (ai,bi)放在前面更优,证明如下( 2014 2014 2014年北京市高考理科数学第 20 20 20题第 2 2 2问):

c 1 = a 1 + b 1 c_1=a_1+b_1 c1=a1+b1
c 2 = m a x ( c 1 , a 1 + a 2 ) + b 1 = m a x ( a 1 + b 1 , a 1 + a 2 ) + b 2 c_2=max(c_1,a_1+a_2)+b_1=max(a_1+b_1,a_1+a_2)+b_2 c2=max(c1,a1+a2)+b1=max(a1+b1,a1+a2)+b2
c 2 = m a x ( a 1 + b 1 + b 2 , a 1 + a 2 + b 2 ) c_2=max(a_1+b_1+b_2,a_1+a_2+b_2) c2=max(a1+b1+b2,a1+a2+b2)
c 3 = m a x ( c 2 , a 1 + a 2 + a 3 ) + b 3 c_3=max(c_2,a_1+a_2+a_3)+b_3 c3=max(c2,a1+a2+a3)+b3
c 3 = m a x ( a 1 + b 1 + b 2 , a 1 + a 2 + b 2 , a 1 + a 2 + a 3 ) + b 3 c_3=max(a_1+b_1+b_2,a_1+a_2+b_2,a_1+a_2+a_3)+b_3 c3=max(a1+b1+b2,a1+a2+b2,a1+a2+a3)+b3
c 3 = m a x ( a 1 + b 1 + b 2 + b 3 , a 1 + a 2 + b 2 + b 3 , a 1 + a 2 + a 3 + b 3 ) c_3=max(a_1+b_1+b_2+b_3,a_1+a_2+b_2+b_3,a_1+a_2+a_3+b_3) c3=max(a1+b1+b2+b3,a1+a2+b2+b3,a1+a2+a3+b3)
综上,我们可以发现一个规律:

我们记 S n ( k ) S_n(k) Sn(k) ∑ i = 1 k a i + ∑ i = k n b i \sum_{i=1}^ka_i+\sum_{i=k}^nb_i i=1kai+i=knbi

那么 c i = m a x ( S i ( 1 ) , S i ( 2 ) , S i ( 3 ) , . . . , S i ( i ) ) c_i=max(S_i(1),S_i(2),S_i(3),...,S_i(i)) ci=max(Si(1),Si(2),Si(3),...,Si(i))

但这只是我们找出来的规律,下面给出严谨证明:

我们考虑用一个 2 ∗ n 2*n 2n的矩阵来表示我们的序列 ( a 1 , b 1 ) , ( a 2 , b 2 ) , . . . , ( a n , b n ) (a_1,b_1),(a_2,b_2),...,(a_n,b_n) (a1,b1),(a2,b2),...,(an,bn)

c 3 c_3 c3为例,我们来画出这些走法,它们分别对应所有的 S S S

[ a 1 a 2 a 3 ↓ b 1 → b 2 → b 3 ] \begin{bmatrix} a_1 && a_2 &&a_3 \\↓\\ b_1 &→& b_2&→ &b_3 \end{bmatrix}\\ a1b1a2b2a3b3
[ a 1 → a 2 a 3 ↓ b 1 b 2 → b 3 ] \begin{bmatrix} a_1 &→& a_2 &&a_3 \\&&↓\\ b_1 && b_2&→ &b_3 \end{bmatrix}\\ a1b1a2b2a3b3
[ a 1 → a 2 → a 3 ↓ b 1 b 2 b 3 ] \begin{bmatrix} a_1 &→& a_2 &→&a_3 \\&&&&↓\\ b_1 && b_2& &b_3 \end{bmatrix}\\ a1b1a2b2a3b3
所以 c n c_n cn在我们的矩阵里表示从 a 1 a_1 a1 b n b_n bn n n n条路径中 n + 1 n+1 n+1个数字和的最大值。

我们用数学归纳法证明 c i = m a x ( S i ( 1 ) , S i ( 2 ) , S i ( 3 ) , . . . , S i ( i ) ) c_i=max(S_i(1),S_i(2),S_i(3),...,S_i(i)) ci=max(Si(1),Si(2),Si(3),...,Si(i))

n = 1 n=1 n=1时, c 1 = m a x ( S 1 ( 1 ) ) c_1=max(S_1(1)) c1=max(S1(1)),显然成立。

假设当 n = k ( k ≥ 1 ) n=k(k\ge1) n=k(k1)时,命题成立,即 c k = m a x ( S k ( 1 ) , S k ( 2 ) , S k ( 3 ) , . . . , S k ( k ) ) c_k=max(S_k(1),S_k(2),S_k(3),...,S_k(k)) ck=max(Sk(1),Sk(2),Sk(3),...,Sk(k))

那么当 n = k + 1 n=k+1 n=k+1时,

c k + 1 = m a x ( c k , a 1 + a 2 + . . . + a k + 1 ) + b k + 1 c_{k+1}=max(c_k,a_1+a_2+...+a_{k+1})+b_{k+1} ck+1=max(ck,a1+a2+...+ak+1)+bk+1
b k + 1 b_{k+1} bk+1带入 m a x max max
c k + 1 = m a x ( c k + b k + 1 , a 1 + a 2 + . . . + a k + 1 + b k + 1 ) c_{k+1}=max(c_k+b_{k+1},a_1+a_2+...+a_{k+1}+b_{k+1}) ck+1=max(ck+bk+1,a1+a2+...+ak+1+bk+1)
合并后面的项
c k + 1 = m a x ( c k + b k + 1 , S k + 1 ( k + 1 ) ) c_{k+1}=max(c_k+b_{k+1},S_{k+1}(k+1)) ck+1=max(ck+bk+1,Sk+1(k+1))
c k c_k ck拆开
c k + 1 = m a x ( S k ( 1 ) + b k + 1 , S k ( 2 ) + b k + 1 , . . . , S k ( k ) + b k + 1 , S k + 1 ( k + 1 ) ) c_{k+1}=max(S_k(1)+b_{k+1},S_k(2)+b_{k+1},...,S_k(k)+b_{k+1},S_{k+1}(k+1)) ck+1=max(Sk(1)+bk+1,Sk(2)+bk+1,...,Sk(k)+bk+1,Sk+1(k+1))
按照 S S S的定义合并所有项
c k + 1 = m a x ( S k + 1 ( 1 ) , S k + 1 ( 2 ) , . . . , S k + 1 ( k + 1 ) ) c_{k+1}=max(S_{k+1}(1),S_{k+1}(2),...,S_{k+1}(k+1)) ck+1=max(Sk+1(1),Sk+1(2),...,Sk+1(k+1))
原命题得证。

下一步,我们来证明如果 m i n ( a i , b j ) ≤ m i n ( a j , b i ) min(a_i,b_j)\le min(a_j,b_i) min(ai,bj)min(aj,bi),那么我们将 ( a i , b i ) (a_i,b_i) (ai,bi)放在前面更优。

考虑上文提到的矩阵,我们对于一个矩阵
[ a 1 a 2 a 3 . . . a n b 1 b 2 b 3 . . . b n ] \begin{bmatrix} a_1 & a_2 &a_3 &...&a_n\\\\ b_1 & b_2&b_3&...&b_n \end{bmatrix}\\ a1b1a2b2a3b3......anbn
我们如果调换两人的顺序,也就是调换矩阵中两列的顺序。

我们假设调换第 k k k列和第 k + 1 k+1 k+1列,我们得到一个新矩阵

[ a 1 ′ a 2 ′ a 3 ′ . . . a n ′ b 1 ′ b 2 ′ b 3 ′ . . . b n ′ ] \begin{bmatrix} a_1' & a_2' &a_3' &...&a_n'\\\\ b_1' & b_2'&b_3'&...&b_n' \end{bmatrix}\\ a1b1a2b2a3b3......anbn
其中
[ a i b i ] = [ a i ′ b i ′ ] ( 1 ≤ i ≤ n 且 i ≠ k , i ≠ k + 1 ) \begin{bmatrix} a_i \\\\ b_i \end{bmatrix}=\begin{bmatrix} a_i' \\\\ b_i' \end{bmatrix}\quad(1\le i\le n且i≠k,i≠k+1) aibi=aibi(1ini=k,i=k+1)
[ a k b k ] = [ a k + 1 ′ b k + 1 ′ ] \begin{bmatrix} a_k \\\\ b_k \end{bmatrix}=\begin{bmatrix} a_{k+1}' \\\\ b_{k+1}' \end{bmatrix}\quad akbk=ak+1bk+1
[ a k + 1 b k + 1 ] = [ a k ′ b k ′ ] \begin{bmatrix} a_{k+1} \\\\ b_{k+1} \end{bmatrix}=\begin{bmatrix} a_{k}' \\\\ b_{k}' \end{bmatrix}\quad ak+1bk+1=akbk
我们记 S n ′ ( k ) S_n'(k) Sn(k) ∑ i = 1 k a i ′ + ∑ i = k n b i ′ , c n ′ = m a x ( S n ′ ( 1 ) , S n ′ ( 2 ) , . . . , S n ′ ( n ) ) \sum_{i=1}^ka_i'+\sum_{i=k}^nb_i',c'_n=max(S_n'(1),S_n'(2),...,S_n'(n)) i=1kai+i=knbi,cn=max(Sn(1),Sn(2),...,Sn(n))

我们设 σ = S n ( k − 1 ) = S n ′ ( k − 1 ) = ∑ i = 1 k − 1 a i + ∑ i = k + 2 n b i = ∑ i = 1 k − 1 a i ′ + ∑ i = k + 2 n b i ′ \sigma=S_n(k-1)=S_n'(k-1)=\sum_{i=1}^{k-1}a_i+\sum_{i=k+2}^{n}b_i=\sum_{i=1}^{k-1}a_i'+\sum_{i=k+2}^{n}b_i' σ=Sn(k1)=Sn(k1)=i=1k1ai+i=k+2nbi=i=1k1ai+i=k+2nbi,那么我们有:

S n ( k ) = σ + a k + b k + b k + 1 S_n(k)=\sigma+a_k+b_k+b_{k+1} Sn(k)=σ+ak+bk+bk+1
S n ( k + 1 ) = σ + a k + a k + 1 + b k + 1 S_n(k+1)=\sigma+a_k+a_{k+1}+b_{k+1} Sn(k+1)=σ+ak+ak+1+bk+1
S n ′ ( k ) = σ + a k ′ + b k ′ + b k + 1 ′ = σ + a k + 1 + b k + 1 + b k S_n'(k)=\sigma+a_k'+b_k'+b_{k+1}'=\sigma+a_{k+1}+b_{k+1}+b_k Sn(k)=σ+ak+bk+bk+1=σ+ak+1+bk+1+bk
S n ′ ( k + 1 ) = σ + a k ′ + a k + 1 ′ + b k + 1 ′ = σ + a k + 1 + a k + b k S_n'(k+1)=\sigma+a_k'+a_{k+1}'+b_{k+1}'=\sigma+a_{k+1}+a_k+b_k Sn(k+1)=σ+ak+ak+1+bk+1=σ+ak+1+ak+bk
m = m i n ( a k , a k + 1 , b k , b k + 1 ) , M = m a x ( S n ( k ) , S n ( k + 1 ) , S n ′ ( k ) , S n ′ ( k + 1 ) ) m=min(a_k,a_{k+1},b_k,b_{k+1}),M=max(S_n(k),S_n(k+1),S_n'(k),S_n'(k+1)) m=min(ak,ak+1,bk,bk+1),M=max(Sn(k),Sn(k+1),Sn(k),Sn(k+1))

我们分别讨论 m m m的取值,

m = a k m=a_k m=ak时,依照上文推出的 S , S ′ S,S' S,S的表达式, M = S n ′ ( k ) M=S_n'(k) M=Sn(k),所以 m a x ( S n ′ ( k ) , S n ′ ( k + 1 ) ) ≥ m a x ( S n ( k ) , S n ( k + 1 ) ) max(S'_n(k),S_n'(k+1))\ge max(S_n(k),S_n(k+1)) max(Sn(k),Sn(k+1))max(Sn(k),Sn(k+1)),即 c n ′ ≥ c n c_n'\ge c_n cncn

其余三种情况同理。

最后我们得出当 m = a k 或 b k + 1 m=a_k或b_{k+1} m=akbk+1时, c n ≤ c n ′ c_n\le c_n' cncn,所以不应交换。

m = a k + 1 或 b k m=a_{k+1}或b_k m=ak+1bk时, c n ≥ c n ′ c_n\ge c_n' cncn,此时应交换 k 与 k + 1 k与k+1 kk+1两列。

相邻两数间的情况可以方便的推广到任意两数交换的情况。

证毕。

从得到的式子 m i n ( a i , b j ) ≤ m i n ( a j , b i ) min(a_i,b_j)\le min(a_j,b_i) min(ai,bj)min(aj,bi)可以看出,我们只需按这个条件排序后模拟即可。

但是,我们这样做是不严谨的。考虑这样一组数据,

7 3
1 1
1 6

显然满足上式,答案输出是 17 17 17

但是我们可以换一种排列方式也满足上式,

1 1
1 6
7 3

此时显然也满足,且答案为 12 12 12

为什么会出现这种情况呢?

原因就是这个式子不满足传递性,交换一次这样的式子对后面确实不会产生什么影响,但如果多交换几次答案可能就会变。

我们考虑对于一些数,如果某一组数排在前面,那么其 a i a_i ai必定越小越好,其 b i b_i bi必定越大越好。

我们按照 a 与 b a与b ab的大小关系将其分为 3 3 3组:
{ a i < b i , a j < b j , 按 a 升 序 排 序 ① a i = b i , a j = b j , 归 入 情 况 1 中 ② a i > b i , a j > b j , 按 a 降 序 排 序 ③ \left\{ \begin{aligned} a_ib_i,a_j>b_j,按a降序排序\qquad③\\ \end{aligned} \right. ai<bi,aj<bj,aai=bi,aj=bj,1ai>bi,aj>bj,a

由于题目中描述的式子是 c i = m a x ( c i − 1 , ∑ i = 1 j a j ) + b i c_i=max(c_{i-1},\sum_{i=1}^j a_j)+b_i ci=max(ci1,i=1jaj)+bi,所以按照贪心的思路,我们先分情况在块内排序,再按照 ① ② ③ ①②③ 的顺序排序,之后模拟即可。

#include
#define int long long
using namespace std;
struct Node{
	int a,b,d;
}f[50005];
int c[50005];
bool cmp(Node x,Node y){
	if(x.d!=y.d)  return x.d<y.d;
	if(x.d<=0)  return x.a<y.a;
	return x.b>y.b;
}
signed main(){
	int T;
	scanf("%lld",&T);
	while(T--){
		int n;
		scanf("%lld",&n);
		for(int i=1;i<=n;i++){
			scanf("%lld%lld",&f[i].a,&f[i].b);
			if(f[i].a>f[i].b)  f[i].d=1;
			if(f[i].a==f[i].b)  f[i].d=0;
			if(f[i].a<f[i].b)  f[i].d=-1;
		}
		sort(f+1,f+n+1,cmp);
		int s=0;
		for(int i=1;i<=n;i++){
			s+=f[i].a;
			c[i]=max(c[i-1],s)+f[i].b;
		}
		cout<<c[n]<<endl;
	}
}

T3:异或(原大新闻)

传送门

题意简述

有两个数 x , y x,y x,y,其中 x x x是随机生成的 [ 0 , n ) [0,n) [0,n)间一个正整数, y y y p p p的概率为 [ 0 , n ) [0,n) [0,n)间一个数,使得 x   x o r   y x\space xor\space y x xor y最大,有 ( 1 − p ) (1-p) (1p)的概率生成方式同 x x x,求 x   x o r   y x\space xor \space y x xor y的期望值。

解题思路

我们先考虑暴力的解法。

35pts

n ≤ 100 n\le100 n100,随便怎么暴力都可以过。

p = 0 p=0 p=0时,即求

∑ i = 1 n ∑ j = 1 n i   x o r   j n 2 \frac{\sum_{i=1}^n\sum_{j=1}^n i\space xor\space j}{n^2} n2i=1nj=1ni xor j

直接两重循环求解即可,时间复杂度 O ( n 2 ) O(n^2) O(n2),记得开 d o u b l e double double

p = 1 p=1 p=1时,我们只需对上述情况的第二层循环做出微调,将求和改为求最大值,再讲每一个 i i i所对应的最大值分别相加即可。

代码略。

50pts

我们可以观察到后面 15 p t s 15pts 15pts的数据是 2 k 2^k 2k的形式,那么它们间一定有着一些特殊规律。

打表检验得:

p = 0 p=0 p=0时,答案为 n − 1 2 \frac{n-1}{2} 2n1

p = 1 p=1 p=1时,答案为 n − 1 n-1 n1

下面给出证明:

首先,在 p = 1 p=1 p=1时,对于每个数 x x x,总有一个数 y ∈ [ 0 , n ) y∈[0,n) y[0,n)使得 x   x o r   y = n − 1 x\space xor \space y=n-1 x xor y=n1,所以期望为 n ( n − 1 ) n = n − 1 \frac{n(n-1)}{n}=n-1 nn(n1)=n1

p = 0 p=0 p=0时,我们首先有一个结论:
x   x o r   i + x   x o r   ( 2 k − i − 1 ) = 2 k − 1 i ∈ [ 0 , 2 k ) x\space xor\space i+x\space xor\space (2^k-i-1)=2^k-1\qquad i∈[0,2^k) x xor i+x xor (2ki1)=2k1i[0,2k)

证明也很简单,手玩一下就好了。

所以我们对 [ 0 , n ) [0,n) [0,n)间数两两配对,求得期望为 n × n × ( n − 1 ) 2 n 2 = n − 1 2 \frac{n\times \frac{n\times(n-1)}{2}}{n^2}=\frac{n-1}{2} n2n×2n×(n1)=2n1

100pts

由于这里有 0 ≤ p ≤ 1 0\le p\le1 0p1的情况,所以我们要先解决这种情况。

P P P为总的期望值, P 1 P_1 P1 p p p 0 0 0时的期望, P 2 P_2 P2 p p p 1 1 1时的期望,

由期望的一些基本知识可以很容易的推出

P = ( 1 − p ) × P 1 + p × P 2 P=(1-p)\times P_1+p\times P_2 P=(1p)×P1+p×P2

那么下面就是如何计算 P 1 , P 2 P_1,P_2 P1,P2的问题了。

先讨论 p = 0 p=0 p=0时的情况,

我们设对于两个数异或起来的值,第 i i i位为 1 1 1为事件 A A A,第 j j j位为 1 1 1为事件 B B B,由位运算的性质知 A , B A,B A,B相互独立,故我们可以分开计算。

我们再设从 [ 0 , n ) [0,n) [0,n)中选出一个数,其二进制第 i i i位为 1 1 1的概率为 p i p_i pi,那么刚才的答案就是

∑ i = 0 log ⁡ n 2 × p i × ( 1 − p i ) × 2 i \sum_{i=0}^{\log n}2\times p_i\times (1-p_i)\times2^i i=0logn2×pi×(1pi)×2i

考虑对于区间 [ 0 , 2 k ) [0,2^{k}) [0,2k),一定有区间 [ 0 , 2 k − 1 ) [0,2^{k-1}) [0,2k1)的所有数的第 k k k位均为 0 0 0,区间 [ 2 k − 1 , 2 k ) [2_{k-1},2^k) [2k1,2k)的所有数第 k k k位均为 1 1 1

然后我们考虑区间 [ 0 , n ) [0,n) [0,n),那么必定有区间 [ S × 2 k , S × 2 k + 2 k − 1 ) [S\times 2^{k},S\times2^k+2^{k-1}) [S×2k,S×2k+2k1)中的数第 k k k位为0,区间 [ S × 2 k + 2 k − 1 , ( S + 1 ) × 2 k + 1 ) [S\times2^k+2^{k-1},(S+1)\times2^{k+1}) [S×2k+2k1,(S+1)×2k+1)中数的第 k k k位为0,所以第 k k k位为1的数的个数是:

⌊ n 2 k + 1 ⌋ × 2 k + m a x ( n   m o d   2 k + 1 − 2 k , 0 ) \lfloor\frac{n}{2^{k+1}}\rfloor\times 2^k+max(n\space mod\space2^{k+1}-2^k,0) 2k+1n×2k+max(n mod 2k+12k,0)

故概率 p i p_i pi
⌊ n 2 k + 1 ⌋ × 2 k + m a x ( n   m o d   2 k + 1 − 2 k , 0 ) n \frac{\lfloor\frac{n}{2^{k+1}}\rfloor\times 2^k+max(n\space mod\space2^{k+1}-2^k,0)}{n} n2k+1n×2k+max(n mod 2k+12k,0)
时间复杂度 O ( log ⁡ n ) O(\log n) O(logn)

我们再来考虑 p = 1 p=1 p=1时的情况(比较毒瘤

我们设 f ( x ) f(x) f(x) [ 0 , n ) [0,n) [0,n)内使 x   x o r   f ( x ) x\space xor\space f(x) x xor f(x)最大的 f ( x ) f(x) f(x)的值

如果没有范围的限制的话, f ( x ) f(x) f(x)应为 x x x按位取反后的值,现在多了一个 n n n的限制,那我们可以考虑用一种贪心的手法保留高位的 1 1 1,如果某一位取 1 1 1会使 f ( x ) ≥ n f(x)\ge n f(x)n,那么这一位就只能取 0 0 0

我们考虑最高的 i − 1 i-1 i1 ( i − 1 ≥ 0 ) (i-1\ge0) (i10) n − 1 n-1 n1的前 ( i − 1 ) (i-1) (i1)位相同的所有的 x x x对答案的贡献,我们考虑 n − 1 n-1 n1 x x x的第 i i i位,有下列情况:

1. n − 1 1.n-1 1.n1的第 i i i位为 0 0 0,由于 x ≤ n − 1 , f ( x ) ≤ n − 1 x\le n-1,f(x)\le n-1 xn1,f(x)n1,所以 x x x的第 i i i位和 f ( x ) f(x) f(x)的第 i i i位必须为 0 0 0

2. n − 1 2.n-1 2.n1的第 i i i位为 1 1 1,那么 x x x i i i位的取值又可以分两种情况:

: x :x :x的第 i i i位为 1 1 1,那么 f ( x ) f(x) f(x)的第 i i i位为 0 0 0,且以后的位数一定可以取 x x x取反后的值。

: x :x :x的第 i i i位为 0 0 0,那么 f ( x ) f(x) f(x)的第 i i i位为 1 1 1,但还有后面的限制。

每次处理时 n − 1 n-1 n1的规模将减半,故时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn)

Code

#include
#define ll long long
using namespace std;
double solve1(ll n){
	double ret=0;
	ll Pow=0,tmp=n-1;
	while(tmp!=0){
		Pow++;
		tmp>>=1;
	}
	for(int i=Pow;i>0;i--){
		ll nw=(n>>i)*(1LL<<i-1)+min(n-(n>>i<<i),1LL<<i-1);
		double p=double(n-nw)/n;
		ret+=(1.0-p)*(1LL<<(i-1))*p;
	}
	return ret*2.0;
}
double solve2(ll n){
	if(n==1)  return 0.0;
	double ret=0.0;
	ll v=1LL,delta,num,tmp=n-1;
	n--;
	while(v<=tmp){
		v<<=1;
	}
	delta=v-1LL;
	v>>=1;
	ret+=(double)delta*(n-v+1);
	ret+=(double)v*v;
	num=v,delta>>=1;
	while(v!=1){
		v>>=1,delta>>=1;
		if(n&v){
			ret+=(double)num*v;
			ret+=(double)(num>>1)*delta;
			num>>=1;
		}
		else
		  ret+=(double)(num>>1)*v;
	}
	return ret/(double)(n+1);
}
int main(){
	ll n;
	double p;
	scanf("%lld%lf",&n,&p);
	double p1=solve1(n),p2=solve2(n),ans=(1.0-p)*p1+p*p2;
	printf("%.6lf\n",ans);
}

你可能感兴趣的:(总结,模拟赛)