WXHRound#13被虐记

来源:互联网 发布:seo软文写作技巧 编辑:程序博客网 时间:2024/06/05 05:00
T1:
给定一个大小为 n 的有根树。有 Q个询问,每次给出一个 k,求至少用多少条长度不超过 k 的祖先-后代链可以覆盖树上的所有点?
n, Q <= 10^5

算法一:不同答案只有sqrt(n)种,拿分治弄一下就是O(nsqrt(n)log(n))
算法二:(本来已经想到这个东西了的。。。)答案一定小于t+(n-t)/k+1(t为叶子数),故可以O(答案-t)的去算每个k。具体算法如下:
我们定义 d[i] 表示点 i和最近的叶子之间的距离
对一个特定的 k,我们只需要将所有d[i] = k 的点加入优先队列,每次将最深的拿出来,若他还没覆盖就覆盖他的k-1个祖先,并插入第k祖先,就能找到解。
T2:
一个长度为 n 的排列,随机执行 k次交换两元素操作
接着,从前向后扫描排列求最大值,问最大值被更新次数的期望
n <= 100, k<= 80
这个题真巧妙。。。(某WXH说是一眼秒
枚举每个数的贡献,枚举每个位置的贡献都不行,那就枚举每个数在每个位置的贡献!
这样假设要计算x在y的贡献,就设f[i][j][0/1/2/3/4]表示到第i次交换,[1,y-1]有j个数小于x
1/3:x在[1,y-1] 0/2:x在[y+1,n] 0/1:a[y]<x 2/3:a[y]>x 4:a[y]=x
转移可以看代码:

#include<bits/stdc++.h>#define mod 1000000007using namespace std;int f[2][110][5],a[110],n,inv,k,ans;int qpow(int a,int b){int ans=1,tmp=a;for(;b;b>>=1,tmp=1ll*tmp*tmp%mod)if(b&1)ans=1ll*ans*tmp%mod;return ans;}void add(int& x,int a){if((x+=a)>=mod)x-=mod;}int calc(int x,int y){for(int i=0;i<2;++i)for(int j=0;j<=n;++j)for(int k=0;k<5;++k)f[i][j][k]=0;int bgj=0,bgs=0,p=0,np=1,WXH=(y-1)*(y-1)+(n-y)*(n-y)+1;for(int i=1;i<y;++i)bgj+=a[i]<x,bgs|=a[i]==x;bgs=!bgs;f[np][bgj][a[y]==x?4:((a[y]>x)<<1|bgs)]=1;for(int i=1;i<=k;++i,swap(p,np))for(int j=0;j<y&&j<x;++j)for(int k=0;k<5;++k)if(f[np][j][k]){int ls=j,lb=y-1-ls-(k==0||k==2),rs=x-1-j-(k==0||k==1),rb=n-y-rs-(k==1||k==3);if(ls<0||lb<0||rs<0||rb<0)continue;f[p][j][k]=(f[p][j][k]+1ll*(WXH+ls*rs*2+lb*rb*2)*f[np][j][k])%mod;if(j)f[p][j-1][k]=(f[p][j-1][k]+2ll*ls*rb*f[np][j][k])%mod;f[p][j+1][k]=(f[p][j+1][k]+2ll*lb*rs*f[np][j][k])%mod;if(k==4){if(j)f[p][j-1][0]=(f[p][j-1][0]+2ll*ls*f[np][j][k])%mod;f[p][j][1]=(f[p][j][1]+2ll*rs*f[np][j][k])%mod;f[p][j][2]=(f[p][j][2]+2ll*lb*f[np][j][k])%mod;f[p][j][3]=(f[p][j][3]+2ll*rb*f[np][j][k])%mod;} else {if(k&1){if(j)f[p][j-1][k^1]=(f[p][j-1][k^1]+2ll*ls*f[np][j][k])%mod;f[p][j][k^1]=(f[p][j][k^1]+2ll*lb*f[np][j][k])%mod;} else {f[p][j+1][k^1]=(f[p][j+1][k^1]+2ll*rs*f[np][j][k])%mod;f[p][j][k^1]=(f[p][j][k^1]+2ll*rb*f[np][j][k])%mod;}if(k&2){if(j)f[p][j-1][k^2]=(f[p][j-1][k^2]+2ll*ls*f[np][j][k])%mod;f[p][j][k^2]=(f[p][j][k^2]+2ll*rs*f[np][j][k])%mod;f[p][j][k]=(f[p][j][k]+2ll*(lb+rb)*f[np][j][k])%mod;} else {f[p][j+1][k^2]=(f[p][j+1][k^2]+2ll*lb*f[np][j][k])%mod;f[p][j][k^2]=(f[p][j][k^2]+2ll*rb*f[np][j][k])%mod;f[p][j][k]=(f[p][j][k]+2ll*(ls+rs)*f[np][j][k])%mod;}if(k==0)f[p][j+1][4]=(f[p][j+1][4]+2ll*f[np][j][k])%mod;else f[p][j][4]=(f[p][j][4]+2ll*f[np][j][k])%mod;}f[np][j][k]=0;}ans=(ans+f[np][y-1][4])%mod;}int main(){scanf("%d%d",&n,&k);for(int i=1;i<=n;++i)scanf("%d",&a[i]);inv=qpow(n*n,1ll*k*(mod-2)%(mod-1));for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)calc(i,j);printf("%d",1ll*ans*inv%mod);}

T3:(我太菜了。。。)
要对一个长度为 2^m的排列进行归并排序
归并的代码写挂了,递归到长度为 2的区间时,比较器有 1 / 2 的概率会挂掉
支持两个操作:
修改初始排列
询问排序后,指定值在指定位置的概率,m<=16,Q<=100000

考虑递归到长度为 2的区间时的两个数 x、y,不妨设 x < y,观察可知,若此时 x 出现在 y 后边,那么排序的整个过程中,x 将一直在 y 的后边且与 y 相邻
观察二路归并的过程即可得到这个结论
这种情况下,可以理解为 x “变成”了 y+0.5

这样就只用计算一定小于x,一定大于x的对数,推一推就可以用树状数组维护。
#include<bits/stdc++.h>#define maxn 1000100#define mod 1000000007using namespace std;int fac[maxn]={1},inv[maxn]={1},tr[2][maxn],n,Q,a[maxn],inv2;int qpow(int a,int b){int ans=1,tmp=a;for(;b;b>>=1,tmp=1ll*tmp*tmp%mod)if(b&1)ans=1ll*ans*tmp%mod;return ans;}void modify(int x,int a,int p){for(;x<=n;x+=x&-x)tr[p][x]+=a;}int query(int x,int p){int ans=0;for(;x;x-=x&-x)ans+=tr[p][x];return ans;}int C(int x,int y){if(x>y||x<0)return 0;return 1ll*fac[y]*inv[x]%mod*inv[y-x]%mod;}int cal(int a1,int y,int z){return 1ll*C(y-a1,z)*qpow(inv2,z)%mod*inv2%mod;}int main(){//freopen("sort2.in","r",stdin);//freopen("s.out","w",stdout);scanf("%d",&n);for(int i=0;i<n;++i)scanf("%d",&a[i]);scanf("%d",&Q);for(int i=1;i<=n;++i)fac[i]=1ll*fac[i-1]*(i)%mod;inv[n]=qpow(fac[n],mod-2);for(int i=n-1;i>=1;--i)inv[i]=1ll*inv[i+1]*(i+1)%mod;for(int i=0;i<n;i+=2)modify(max(a[i],a[i^1]),1,0),modify(n-min(a[i],a[i^1]),1,1);int all=n>>1;inv2=qpow(2,mod-2);for(int i=1,op,x,y;i<=Q;++i){scanf("%d%d%d",&op,&x,&y);if(op==1){x--,y--;modify(max(a[x],a[x^1]),-1,0);modify(n-min(a[x],a[x^1]),-1,1);modify(max(a[y],a[y^1]),-1,0);modify(n-min(a[y],a[y^1]),-1,1);swap(a[x],a[y]);modify(max(a[x],a[x^1]),1,0);modify(n-min(a[x],a[x^1]),1,1);modify(max(a[y],a[y^1]),1,0);modify(n-min(a[y],a[y^1]),1,1);} else {x--,y--;int ans=0;if(a[x]>a[x^1]){int a1=query(a[x],0)-(max(a[x],a[x^1])<=a[x]);int a2=query(n-a[x],1)-(min(a[x],a[x^1])>=a[x]);//printf("[%d,%d,%d,%d]",a1,a2,y-a1*2);ans=(cal(a1*2,y,all-a1-a2-1)+cal(a1*2+1,y,all-a1-a2-1))%mod;printf("%d\n",ans);} else {int a1=query(a[x],0)-(max(a[x],a[x^1])<=a[x]);int a2=query(n-a[x],1)-(min(a[x],a[x^1])>=a[x]);int a3=query(a[x^1],0)-(max(a[x],a[x^1])<=a[x^1]);int a4=query(n-a[x^1],1)-(min(a[x],a[x^1])>=a[x^1]);//printf("[%d,%d,%d,%d]",a1,a2,y-a1*2);ans=(cal(a1*2,y,all-a1-a2-1)+cal(a3*2+1,y,all-a3-a4-1))%mod;printf("%d\n",ans);}}//return 0;}}



原创粉丝点击