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;
}