数独
咕咕咕
分糖果
交换两个找结论,证明贪心。发现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;
}
异或
两个子问题。一个成功,一个不成功。
不成功按位处理,考虑每一位贡献。
明显为
p表示这一位为1的概率。
算这一位为1的有多少个。我们发现每2*2^i=2^{i+1}一个循环节。每个循环节有一半是1,。最后还有个余数随便处理一下。
然后看成功。
对于成功,我们假想一个数位dp出来。
思想1:算到哪一位,我们将这位的贡献算完,这位后面乱搞的贡献算完。这样强制每一位的异或值也要符合n的限制。
分四种情况讨论。一个是x本位是否为1,一个是n本位是否为1。令num为当前还需要讨论的数的个数。
如果n为1{
x==1:则为了贪心得到本位,异或值本位为0,所有后面可以乱搞,贡献为
x==0:则为了贪心得到本位,异或值本位为1,后面不可以乱搞,贡献为
}else{
x==1:则为了贪心得到本位,异或值本位为0,后面不可以乱搞,贡献为
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;
}