csp-plus 20191015 【模拟】【结论+排序】【位运算】

数独

woj4218

咕咕咕

分糖果

woj4219

交换两个找结论,证明贪心。发现min(a,d)<min(b,c)成立。

但实际上如果sort的话,这个结论是不完全正确的。因为不满足传递性和非等式性。

真正的证明见洛谷题解第一个

不过写个最弱的也能过woj。

#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){
		ch=getchar();if(ch=='-')f=-1; 
	}
	while(isdigit(ch)){
		cnt=cnt*10+ch-48;
		ch=getchar();if(ch=='-')f=-1;
	}return cnt*f;
} 

struct node{
	int a,b;
}a[50003];
int t;int n;
bool cm(node a,node b){
	return (min(a.a,b.b)<min(a.b,b.a));
}int ans=0;
int sum[50003];
signed main(){
	t=in;
	while(t--){
		n=in;ans=0;
		for(int i=1;i<=n;i++)a[i].a=in,a[i].b=in;
		sort(a+1,a+n+1,cm);ans=a[1].a+a[1].b;sum[1]=a[1].a;
		//for(int i=1;i<=n;i++)cout<<a[i].a<<" "<<a[i].b<<endl;
		for(int i=2;i<=n;i++){
			sum[i]=0;sum[i]+=a[i].a+sum[i-1];int x=max(ans,sum[i]);ans=x+a[i].b;
		}
		cout<<ans<<'\n';
	}
	return 0;
}

异或

woj4220

两个子问题。一个成功,一个不成功。

不成功按位处理,考虑每一位贡献。

明显为p_i(1-p_i)2^ i

p表示这一位为1的概率。

算这一位为1的有多少个。我们发现每2*2^i=2^{i+1}一个循环节。每个循环节有一半是1,。最后还有个余数随便处理一下。

 

然后看成功。

对于成功,我们假想一个数位dp出来。

思想1:算到哪一位,我们将这位的贡献算完,这位后面乱搞的贡献算完。这样强制每一位的异或值也要符合n的限制。

分四种情况讨论。一个是x本位是否为1,一个是n本位是否为1。令num为当前还需要讨论的数的个数。

如果n为1{

        x==1:则为了贪心得到本位,异或值本位为0,所有后面可以乱搞,贡献为\frac{num}{2}2^{now}+\frac{num}{2}(2^{now}-1)

        x==0:则为了贪心得到本位,异或值本位为1,后面不可以乱搞,贡献为\frac{num}{2}2^{now}

}else{

        x==1:则为了贪心得到本位,异或值本位为0,后面不可以乱搞,贡献为\frac{num}{2}2^{now}

        x==0:则为了贪心得到本位,异或值本位为1,而1不能用,所以贡献为0。

}

第一位特殊处理一下,因为第一位满足n为1,枚举x就可以理解如何特殊处理。

然后乱搞就可以了。

#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){
		ch=getchar();if(ch=='-')f=-1;
	}
	while(isdigit(ch)){
		cnt=cnt*10+ch-48;
		ch=getchar();
	}return cnt*f;
}
int n;double mod;
double ans;
double fail(int n){
	double sum=0.0;int cnt=0;
	for(int _n=n-1;_n;_n>>=1,cnt++);
	for(int i=cnt;i;i--){
		int gu=(n>>i)*(1ll<<i-1)+min(n-(n>>i<<i),1ll<<(i-1));
		double ri=(double)(n-gu)/n;
		sum+=2*ri*(1.0-ri)*(1ll<<i-1);
	}return sum;
} 
double success(int n){
	if(n==1)return 0.0;
	double sum=0.0;int v=1,num,delta;
	for(--n;v<=n;v<<=1);
	delta=v-1;v>>=1;
	sum+=(double)delta*(n-v+1);
	sum+=(double)v*v;
	num=v;delta>>=1;
	while(v!=1){
		v>>=1;delta>>=1;
		if(n&v){
			sum+=(double)num*v;
			sum+=(double)(num>>1)*delta;
			num>>=1;
		}else sum+=(double)(num>>1)*v;
	}return sum/(double)(n+1);
}
signed main(){
	n=in;scanf("%lf",&mod);
	double ans1=fail(n),ans2=success(n);
	ans=(1.0-mod)*ans1+mod*ans2;
	int b=0;
	while(ans>=10.0)ans/=10.0,b++;
	while(ans>0.0&&ans<1.0)ans*=10.0,b--;
	printf("%.5lf %d",ans,b);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值