HDU多校2018第一场部分题目

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章