我居然浪費一下午改題時間作了這個sb題c++
從2.00改到6.00ide
搜索題還要看代碼spa
我是否是廢了code
記憶化,但怎麼記憶化,記憶化劃分狀態不太好劃分,你不知道哪些隊比過了,哪些隊沒有比過blog
也就是隻拿一些隊得分狀況劃分狀態表示不全排序
咱們不能搜到一個狀態,記錄,return,由於會出現當前本應非法但你取用了記憶化的值就錯了內存
有一種作法就是再記錄隊之間比勝過狀態,然而空間不夠get
由於任意兩支隊伍都要比賽一場咱們能夠列出來比賽是下三角類型的,hash
隊伍1 2 3 4it
1 1 1 1 1
2 1 1 1
3 1 1
1 1
枚舉當前比賽隊伍和枚舉的隊伍,(拿4舉例就是枚舉1 2 3和4比賽,而後向前推動到3,枚舉1 2 和3比賽,向前推動到2,枚舉1和2比賽,最後推動到1)
這樣咱們dp定義f[x][state]表示推動到第x列,當前球隊得分狀態是state的得分,有多少種合法方案,這樣咱們能夠間接知道比賽狀況
依然會炸內存,可是能夠hash表維護
當咱們搜完一列時看有沒有記憶化,若是沒有記憶化就接着搜完下一列
再加一些剪枝
可行性剪枝
若是當前還剩x場比賽,球隊i分數a[i],即便x場比賽全贏都得不了a[i]分就return
搜索順序剪枝
sort排序
#include<bits/stdc++.h> using namespace std; #define ll long long #define A 12 const ll modd=1e9+7; pair<ll,ll> e[A*A]; ll a[A]; ll n,cnt,ans; struct Hash_Table{ #define mod 1030829 ll nxt[mod],val[mod],ver[mod],head[mod]; ll tot; ll &operator [](const ll &H){ ll x=H%mod; for(ll i=head[x];i;i=nxt[i]){ if(ver[i]==H) return val[i]; } nxt[++tot]=head[x]; ver[tot]=H; head[x]=tot; return val[tot]; } }H; ll cmp(ll x,ll y){return x>y;} ll gethash(ll x){ ll tmp[11],hh=x; for(ll i=1;i<=x;i++) tmp[i]=a[i]; sort(tmp+1,tmp+x+1); for(ll i=1;i<=x;i++) hh=hh*28+tmp[i]; return hh; } ll dfs(ll x,ll pla){ if(a[pla]>(pla-x)*3) return 0; if(x==pla){ if(pla==1) return 1; else { ll hh=gethash(pla-1); if(H[hh]!=-1) { // printf("h=%lld \n",hh); return H[hh]; } else return H[hh]=dfs(1,pla-1); } } ll d=0; if(a[x]>=3){ a[x]-=3; d+=dfs(x+1,pla); if(d>=modd) d-=modd; a[x]+=3; } if(a[pla]>=3){ a[pla]-=3; d+=dfs(x+1,pla); if(d>=modd) d-=modd; a[pla]+=3; } if(a[x]>=1&&a[pla]>=1){ a[x]--,a[pla]--; d+=dfs(x+1,pla); if(d>=modd) d-=modd; a[x]++,a[pla]++; } return d; } int main(){ memset(H.val,-1,sizeof(H.val)); scanf("%lld",&n); for(ll i=1;i<=n;i++) scanf("%lld",&a[i]); sort(a+1,a+n+1,cmp); printf("%lld\n",dfs(1,n)%modd); }
csps退役前,我最後悔的事就是作了這個sb題