题解 P3154 【[CQOI2009]循环赛】

· · 题解

upd on 2025.8.18 修复 latex

\begin{cases} 3x+2y=\sum_{i=1}^n a_i\\ x+y=\frac{n\times(n-1)}{2}\\ \end{cases} \begin{cases} x=-n\times(n-1)+\sum_{i=1}^n a_i\\ y=\frac{3n\times(n-1)}{2}-\sum_{i=1}^na_i\\ \end{cases} \sf{Code}
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define re register
#define N 101001
#define MAX 2001
#define inf 1e18
using namespace std; 
typedef int ll;
typedef double db;
const ll mod=1000000007;
inline void read(re ll &ret)
{
    ret=0;re char c=getchar();re bool pd=false;
    while(!isdigit(c)){pd|=c=='-';c=getchar();}
    while(isdigit(c)){ret=(ret<<1)+(ret<<3)+(c&15);c=getchar();};
    ret=pd?-ret:ret;
    return;
}
ll n,a[N],ans,allx,ally,val[N],st[N];
ll b[MAX][MAX];
map<ll,ll>mp;
inline bool cmp(re ll x,re ll y)
{
    return x>y;
}
inline ll dfs(re ll x,re ll y,re ll nowx,re ll nowy)
{
    if(x==n)
        return 1;
    if(val[x]+(n-y+1)*3<a[x])
        return 0;
    if(y>n)
    {
        for(re int i=x+1;i<=n;i++)
            st[i]=a[i]-val[i];
        sort(st+x+1,st+n+1);
        re ll now=0;
        for(re int i=x+1;i<=n;i++)
            now=now*28+st[i];
        if(mp.find(now)!=mp.end())
            return mp[now];
        return mp[now]=dfs(x+1,x+2,nowx,nowy);
    }
    re ll ret=0;
    if(val[y]+3<=a[y]&&nowx)
        val[y]+=3,ret+=dfs(x,y+1,nowx-1,nowy),ret%=mod,val[y]-=3;
    if(val[x]+1<=a[x]&&val[y]+1<=a[y]&&nowy)
        val[x]++,val[y]++,ret+=dfs(x,y+1,nowx,nowy-1),ret%=mod,val[x]--,val[y]--;
    if(val[x]+3<=a[x]&&nowx)
    val[x]+=3,ret+=dfs(x,y+1,nowx-1,nowy),ret%=mod,val[x]-=3;
    return ret;
}
ll sum;
signed main()
{
    read(n);
    for(re int i=1;i<=n;i++)
        read(a[i]),sum+=a[i];
    allx=sum-n*n+n;
    ally=((sum-3*allx)>>1);
    sort(a+1,a+n+1,cmp);
    printf("%d\n",dfs(1,2,allx,ally));
    exit(0);
}