正题
这次比赛打得不错,想出了两道题,期望230,实际180。
T1
其实挺好玩的,考虑到^0,|0,&1之后数值不会改变,^1翻转,|1变成1,&0变成0。
把第一个数位可以换成|?,然后规定开始为0。
考虑到一个操作序列,有用的位置一定是最后一个“变成”和最后一些翻转,想到可以枚举最后一个变成是哪个位置,该位置前面所有数位随便取,后面的翻转个数为奇数或偶数,其他不变,那么这个就是一个组合数奇/偶数位之和,除了0的情况比较特殊,其他的肯定都是,二项式定理即可证明。
结果比赛的时候手残写了一个错的对拍,交了一个错的观察程序。(还能水到30分
#include<bits/stdc++.h>
using namespace std;
const int N=10000010;
char s[N];
long long ci[N];
int n;
const long long mod=1e9+7;
int main(){
scanf("%d",&n);
scanf("%s",s+1);s[0]='|';
ci[0]=1;for(int i=1;i<=n;i++) ci[i]=ci[i-1]*2%mod;
long long ans=0,t=0;
for(int i=n;i>=0;i--) if(s[i]=='^') t++;else{
if(t==0 && s[i]=='&') continue;
else if(t==0) ans+=ci[i];
else ans+=ci[i]*ci[t-1]%mod;
}
if(t) ans+=ci[t-1];
printf("%lld",ans%mod);
}
T2
首先要会做一种情况的,直接离散化以后用一个树状数组去维护就可以了,两种情况就分开讨论就可以了,互相必定没有影响。离散化懒得可以map。
#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;
const int N=100010;
int mmax1[N<<1],mmax2[N<<1],n,ans,t,tmp;
int x[N],y[N];
map<int,int> mp;
map<int,int>::iterator it;
void change(int*a,int x,int c){
while(x<=t){
a[x]=max(a[x],c);
x+=lowbit(x);
}
}
int get_max(int*a,int x){
int mmax=0;
while(x){
mmax=max(mmax,a[x]);
x-=lowbit(x);
}
return mmax;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d %d",&x[i],&y[i]),mp[x[i]]=1,mp[y[i]]=1;
for(it=mp.begin();it!=mp.end();it++) (*it).second=++t;
for(int i=1;i<=n;i++) {
x[i]=mp[x[i]],y[i]=mp[y[i]];
if(x[i]==y[i]) continue;
if(x[i]<y[i]){
tmp=get_max(mmax1,t-x[i])+1;
ans=max(ans,tmp);
change(mmax1,t-y[i]+1,tmp);
}
else{
tmp=get_max(mmax2,x[i]-1)+1;
ans=max(ans,tmp);
change(mmax2,y[i],tmp);
}
}
printf("%d",ans);
}
T3
“当他给你输出6位小数而不是模的时候,你就要知道这个题就是来搞你心态的” ---来自Freopen巨神
考虑到往下70层的时候影响十分小,所以我们只用考虑前70层。
期望与概率之间的转化就是
P(x>=i)表示最大层数在i以下的概率,补集转化就可以得到第二条式子。
这个东西可以用一个来维护第i个点往下走不了i层的概率。
转移的时候先考虑去掉前面的影响,在考虑父亲-儿子这条边选或者不选带来的概率。
选的时候,下面必须满足走不到i-1层,并且要满足从其他子树走走不到第i层。
不选的时候,下面没有要求,要满足从其他子树走走不到第i层。
具体写法可以看代码。
那么式子就很好写了,时间复杂度就是
#include<bits/stdc++.h>
using namespace std;
const int N=500010,sz=70;
int T,q,tot,fa[N];
double f[N][sz];
int main(){
scanf("%d %d",&T,&q);tot=1;
fill(f[1]+1,f[1]+sz,1);f[1][0]=0;
int type,x;
while(q--){
scanf("%d %d",&type,&x);
if(type==1){
fa[++tot]=x;
fill(f[tot]+1,f[tot]+sz,1);f[tot][0]=0;
double now,last=1;
for(int i=1,op=tot;x!=0 && i<sz;i++,x=fa[op=x]) now=(f[x][i]+1)/2,f[x][i]*=(f[op][i-1]+1)/2/last,last=now;
}
else{
double ans=0;
for(int i=1;i<sz;i++) ans+=1-f[x][i];
printf("%.10lf\n",ans);
}
}
}