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