• bzoj 3139: [Hnoi2013]比赛


    Description

    沫沫非常喜欢看足球赛,但因为沉迷于射箭游戏,错过了最近的一次足球联赛。此次联 赛共N支球队参加,比赛规则如下:
    (1) 每两支球队之间踢一场比赛。 (2) 若平局,两支球队各得1分。
    (3) 否则胜利的球队得3分,败者不得分。
    尽管非常遗憾没有观赏到精彩的比赛,但沫沫通过新闻知道了每只球队的最后总得分, 然后聪明的她想计算出有多少种可能的比赛过程。
    譬如有3支球队,每支球队最后均积3分,那么有两种可能的情况:
    可能性1 可能性2
    球队 A B C 得分 球队 A B C 得分
    A - 3 0 3 A - 0 3 3
    B 0 - 3 3 B 3 - 0 3
    C 3 0 - 3 C 0 3 - 3
    但沫沫发现当球队较多时,计算工作量将非常大,所以这个任务就交给你了。请你计算 出可能的比赛过程的数目,由于答案可能很大,你只需要输出答案对109+7取模的结果

    solution

    我是个xlb,这个题目显然需要记忆化,很久以前yy出hash DP一直没用得上,这题显然可以用,我的转移十分作死,转移是唯一的,记忆化没有什么用,其实只需要hash后面的队伍即可,其他基础剪枝看代码,另外队伍是等价的,所以拥有相同剩余分数的队伍是一样的,我们可以默认分数从小到大排序,这样可以减少状态

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <map>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    typedef long long ll;
    const int N=15,mod=1e9+7;
    int n,a[N],m=0,res[N];
    struct node{
       int x,y;
    }e[N*N];
    map<ll,ll>s;
    long long ans=0;
    il bool check(){
       for(RG int i=1;i<=n;i++)
          if(a[i])return false;
       return true;
    }
    il bool judge(){
       for(RG int i=1;i<=n;i++)
          if(3*res[i]<a[i])return true;
       return false;
    }
    int b[N];
    il ll query(int x){
       ll tot=x;int l=0;
       for(int i=x+1;i<=n;i++)b[++l]=a[i];
       sort(b+1,b+l+1);
       for(int i=1;i<=l;i++)
          tot=tot*28+b[i];
       return tot;
    }
    il int dfs(int i){
       if(i==m+1){
          if(check())return 1;
          return 0;
       }
       if(judge())return 0;
       ll li;RG int x=e[i].x,y=e[i].y;ll ans=0;
       if(e[i].x!=e[i-1].x){
          li=query(e[i-1].x);
          if(s.count(li))return s[li];
       }
       res[x]--;res[y]--;
       if(a[x]>=3)a[x]-=3,ans+=dfs(i+1),a[x]+=3;if(ans>=mod)ans-=mod;
       if(a[y]>=3)a[y]-=3,ans+=dfs(i+1),a[y]+=3;if(ans>=mod)ans-=mod;
       if(a[x] && a[y])a[x]--,a[y]--,ans+=dfs(i+1),a[x]++,a[y]++;
       res[x]++;res[y]++;
       if(ans>=mod)ans-=mod;
       if(e[i].x!=e[i-1].x)s[li]=ans;
       return ans;
    }
    void work()
    {
       scanf("%d",&n);
       for(int i=1;i<=n;i++)scanf("%d",&a[i]);
       sort(a+1,a+n+1);
       for(int i=1;i<=n;i++)
          for(int j=i+1;j<=n;j++)
             e[++m].x=i,e[m].y=j;
       for(int i=1;i<=n;i++)res[i]=n-1;
       cout<<dfs(1)<<endl;
    }
     
    int main(){work();return 0;}
    
  • 相关阅读:
    android: 在fragment中添加actionbar, menu
    Android Context
    Android 在fragment中使用tabhost
    Android 菜单
    centos8 防火墙
    DHCP 原理
    阿里云服务器 linux下载 jdk
    java long值转成时间格式
    Window 中杀死指定端口 cmd 命令行 taskkill
    redis 安装
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7677285.html
Copyright © 2020-2023  润新知