HDU多校2018第一场部分题目
这场过了7题,剩下的题大概再给点时间也做不出来。
还算可以吧。
E aximum Weighted Matching(hdu 6302)
题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6302
题解
给你一张无向图,求最大权匹配。
这张图的生成方法比较奇怪,初始有一条边,每次在原图中选一条边,加入一条链。
考虑把操作倒过来,每次选一个度为2的点,把它的左右两条边删掉,再连上一条虚边。
这样就可以还原出构图的过程。
考虑在这张图上求最大权匹配,我们以边建立状态,f[edge][x][y]表示edge这条边的两个端点,是否被匹配的最大权匹配。
然后转移一下就好了。
说起来很简单,一点都不好写。。。
代码
#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
#define N 100010
using namespace std;
int T,n,m,tot,po[N],tag[N*4],k,la[N],ff[N*4],d[N];
map<int,int>w[N];
struct node{int b;}e[N*4];
struct info{
ll val;ll size;
info operator+(const info &p){
return (info){val+p.val,(ll)size*p.size%mod};
}
}ans,f[N*4][2][2],g[2][2],h[2][2];
void gmax(info &a,info b)
{
if(b.val==a.val)a.size=(a.size+b.size)%mod;
if(b.val>a.val)a=b;
}
void set_dp(int x,int c)
{
f[x][0][0]=(info){0,1};f[x][0][1]=(info){0,0};
f[x][1][0]=(info){0,0};f[x][1][1]=(info){c,1};
}
void add(int a,int b,int c)
{
if(w[a][b])
{
int ed=w[a][b];
gmax(f[ed][1][1],(info){c,1});
f[ed^1][1][1]=f[ed][1][1];
return;
}
d[a]++;d[b]++;
e[++k]=(node){b};ff[k]=la[a];la[a]=k;
if(c)set_dp(k,c);w[a][b]=k;
e[++k]=(node){a};ff[k]=la[b];la[b]=k;
if(c)set_dp(k,c);w[b][a]=k;
}
int main()
{
int a,b,c,A,B,aa,bb,now;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
k=1;ans=(info){0,0};tot=0;
for(int i=1;i<=n;i++)w[i].clear();
for(int i=1;i<=m;i++)
scanf("%d%d%d",&a,&b,&c),add(a,b,c);
for(int i=1;i<=n;i++)if(d[i]==2)po[++tot]=i;
for(int i=1;i<=tot;i++)
{
int x=po[i],A=0,B=0;
for(int a=la[x];a;a=ff[a])
{
if(tag[a>>1])continue;
if(!A)A=a,aa=e[a].b;
else{B=a;bb=e[a].b;break;}
}
if(!B)continue;
tag[A>>1]=1;tag[B>>1]=1;
for(int a=0;a<=1;a++)
for(int b=0;b<=1;b++)
{
g[a][b]=(info){0,0};
gmax(g[a][b],f[A][0][a]+f[B][0][b]);
gmax(g[a][b],f[A][1][a]+f[B][0][b]);
gmax(g[a][b],f[A][0][a]+f[B][1][b]);
}
if(w[aa][bb])
{
d[aa]--;if(d[aa]==2)po[++tot]=aa;
d[bb]--;if(d[bb]==2)po[++tot]=bb;
now=w[aa][bb];
for(int a=0;a<=1;a++)
for(int b=0;b<=1;b++)
h[a][b]=f[now][a][b],f[now][a][b]=(info){0,0};
f[now][0][0]=h[0][0]+g[0][0];
for(int a=0;a<=1;a++)
{
gmax(f[now][1][0],h[a][0]+g[a^1][0]);
gmax(f[now][0][1],h[0][a]+g[0][a^1]);
gmax(f[now][1][1],h[a][a]+g[a^1][a^1]);
gmax(f[now][1][1],h[a][a^1]+g[a^1][a]);
}
for(int a=0;a<=1;a++)
for(int b=0;b<=1;b++)
f[now^1][b][a]=f[now][a][b];
}
else
{
add(aa,bb,0);now=w[aa][bb];d[aa]--;d[bb]--;
for(int a=0;a<=1;a++)
for(int b=0;b<=1;b++)
f[now][a][b]=f[now^1][b][a]=g[a][b];
}
}
for(int i=2;i<=k;i+=2)
{
if(tag[i>>1])continue;
for(int a=0;a<=1;a++)
for(int b=0;b<=1;b++)gmax(ans,f[i][a][b]);
}
printf("%I64d %I64d\n",ans.val,ans.size);
for(int i=1;i<=n;i++)la[i]=d[i]=0;
for(int i=1;i<=k;i++)tag[i]=ff[i]=0;
}
return 0;
}
H RMQ Similar Sequence(hdu 6305)
题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6305
题解
题目要求B数组的期望和,要求B数组和A数组RMQ相似。
首先B数组数字的取值范围是[0,1]中的任意实数,所以任意两个数相等的概率为0,所以我们只需要考虑所以数字不相等的情况。
我们只需要知道B数组中n个数字的相对大小关系,对于每一组数期望和肯定是n/2。
ans=(n/2)*res/n!。res为合法的相对大小序列数。
所谓RMQ相等其实就是笛卡尔树相等。
所以我们O(n)构造出笛卡尔树,然后求出笛卡尔树的拓扑序列数就好了。
至于拓扑序列数,我们构造出笛卡尔树,res=n/2*πsize[i]。
代码
#include<bits/stdc++.h>
#define _(d) while(d((ch=getchar()-48)>=0))
#define mod 1000000007
#define ll long long
#define N 1000010
using namespace std;
int T,n,rt,s[N],q[N],top;ll ans;
struct node{int lc,rc;}t[N];
inline int get()
{
char ch;_(!);int x=ch;
_()x=x*10+ch;return x;
}
inline ll Pow(ll a,int b)
{
int res=1;
while(b)
{
if(b&1)res=res*a%mod;
a=a*a%mod;b>>=1;
}
return res;
}
ll dfs(int x)
{
int res=1;
if(t[x].lc)res+=dfs(t[x].lc);
if(t[x].rc)res+=dfs(t[x].rc);
ans=(ll)ans*res%mod;
return res%mod;
}
int main()
{
T=get();
while(T--)
{
n=get();ans=1;rt=0;top=0;
for(int i=1;i<=n;i++)t[i].lc=t[i].rc=0;
for(int i=1;i<=n;i++)
{
s[i]=get();
while(s[q[top]]<s[i]&&top)top--;
if(!top)t[i].lc=rt,rt=i;
else t[i].lc=t[q[top]].rc,t[q[top]].rc=i;
q[++top]=i;
}
dfs(rt);
ans=Pow(ans,mod-2)*n%mod*Pow(2,mod-2)%mod;
printf("%d\n",ans);
}
return 0;
}