我居然浪费一下午改题时间作了这个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题