2021牛客暑期多校訓練營9
阿新 • • 發佈:2021-08-23
比賽連結:https://ac.nowcoder.com/acm/contest/11260
E,H,J,10。不錯。
I
分析:
題目意思是,\(A\)和\(B\)搶奪\(n\)塊地盤,一開始\(A\)的能力值是\(a\),\(B\)的能力值是\(b\);每搶上一塊地盤,搶到的人的能力值會增加\(w\)。\(A\)搶上的概率是\( \frac{A的能力值}{當前總能力值} \),\(B\)同。問最終\(A\)搶到地盤數的期望。
於是可以設\(E(x)\)表示經過\(x\)輪後\(A\)的期望能力值。有轉移方程:
\( E(x+1) = E(x) + \frac{E(x)}{1+wx}*w \)
移項可以得到:
\( \frac{E(x+1)}{1+w(x+1)} = \frac{E(x)}{1+wx} = E(0) = a \)
然後答案可以通過最終的能力值得到,因為能力值和搶幾塊地盤直接相關:
\( ans = \frac{E(n)-E(0)}{w} = a*n \)
程式碼如下:
#include<iostream> #define ll long long using namespace std; int const md=998244353; int n,w,x,y; ll pw(int a,int b) { ll ret=1,na=a; while(b) {View Codeif(b&1)ret=(ret*na)%md; na=(na*na)%md; b>>=1; } return ret; } int main() { scanf("%d%d%d%d",&n,&w,&x,&y); ll a=(x*pw(y,md-2))%md; printf("%lld\n",a*n%md); return 0; }
J
分析:
首先,右轉不會影響任何路線,也不會被任何路線影響,所以單獨考慮,最後算答案時比較一下即可。
剩下的就是左轉和直行。觀察一番後可以發現,最多有兩個燈同時亮起,而且只有四種情況:直行+對面直行,左轉+對面左轉,直行+左邊左轉,直行+自己左轉。
換句話說,每個直行有三種燈可以帶:前直,左左,自左;每個左轉有三種燈可以帶:前左,右直,自直。
所以現在問題可以轉化成:預設每個燈單獨亮,然後考慮如何安排使得可以相互帶的燈實現最大匹配。
可以拆點,然後二分圖匹配——由於還有車流量各種,所以網路流跑一個最大流即可。拆點後會有重複的情況,但是都是對稱的,所以直接最大流除以二。
程式碼如下:
#include<iostream> #include<cstring> #include<queue> using namespace std; int const N=20,M=200,inf=100000; int T,n,a[N][N],hd[N],nxt[M],cnt,to[M],w[M],num[N],ed=17; int d[N],cur[N]; queue<int>q; int md(int x){if(x>8)x-=8; return x;} int md2(int x){if(x<=0)x+=8; return x;} void add(int x,int y,int f) { //printf("add(%d,%d)\n",x,y); nxt[++cnt]=hd[x]; hd[x]=cnt; to[cnt]=y; w[cnt]=f; nxt[++cnt]=hd[y]; hd[y]=cnt; to[cnt]=x; w[cnt]=0; } bool bfs() { while(q.size())q.pop(); memset(d,0,sizeof d); q.push(0); d[0]=1; while(q.size()) { int u=q.front(); q.pop(); for(int i=hd[u],v;i>-1;i=nxt[i]) if(!d[v=to[i]]&&w[i])d[v]=d[u]+1,q.push(v); } return d[ed]; } int dfs(int u,int f) { if(u==ed)return f; int res=0; for(int &i=cur[u],v;i>-1;i=nxt[i]) if(d[v=to[i]]==d[u]+1&&w[i]) { int k=dfs(v,min(w[i],f-res)); res+=k; w[i]-=k; w[i^1]+=k; if(res==f)return f; } if(!res)d[u]=0; return res; } int main() { scanf("%d",&T); while(T--) { int lf=0; for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) scanf("%d",&a[i][j]),lf+=a[i][j]; int right=max(a[1][4],max(a[2][1],max(a[3][2],a[4][3]))); lf-=(a[1][4]+a[2][1]+a[3][2]+a[4][3]); num[1]=a[1][3]; num[2]=a[1][2]; num[3]=a[2][4]; num[4]=a[2][3]; num[5]=a[3][1]; num[6]=a[3][4]; num[7]=a[4][2]; num[8]=a[4][1]; cnt=-1; memset(hd,-1,sizeof hd); for(int i=1;i<=8;i++)add(0,i,num[i]),add(i+8,ed,num[i]); for(int i=1;i<=8;i++) { if(i%2) add(i,md(i+4)+8,inf),add(i,md(i+3)+8,inf),add(i,md(i+1)+8,inf);//直:前直,左左,自左 else add(i,md(i+4)+8,inf),add(i,md2(i-3)+8,inf),add(i,md2(i-1)+8,inf);//左:前左,右直,自直 } int flow=0; while(bfs()) { memcpy(cur,hd,sizeof hd); flow+=dfs(0,inf); } printf("%d\n",max(lf-flow/2,right)); } return 0; }View Code