AGC002(D~F)【Kruskal重构树,博弈论,dp】
正題
AT1998 [AGC002D] Stamp Rally【Kruskal重構樹,倍增】
https://www.luogu.com.cn/problem/AT1998
題目大意
給出nnn個點mmm條邊的一張無向圖,qqq次詢問兩個人分別從x,yx,yx,y,要求總共經過zzz個點的情況下經過邊的最大編號的最小值。
1≤n,m,q≤1051\leq n,m,q\leq 10^51≤n,m,q≤105
解題思路
直接上KruskalKruskalKruskal重構樹然后預處理倍增數組和子樹大小。
然后二分答案+倍增判斷就好了,這樣寫是兩個log?\loglog的,直接倍增一個log?\loglog也行但是比較麻煩。
時間復雜度:O(nlog?2n)O(n\log^2n )O(nlog2n)
AT1999 [AGC002E] Candy Piles【博弈論】
https://www.luogu.com.cn/problem/AT1999
題目大意
nnn堆糖果,第iii堆有aia_iai?個,有如下操作
- 取走糖果最多的那堆
 - 所有堆中各取走一個
 
1≤n≤105,1≤ai≤1091\leq n\leq 10^5,1\leq a_i\leq 10^91≤n≤105,1≤ai?≤109
解題思路
考慮如果現在操作的那個人一直用第一個操作會輸那么它肯定會用第二個操作,而此時會轉換勝負態,那么下一個人也會繼續這么做,但是如果到最后一個且剛好是偶數那么使用第一個操作就更優。
所以肯定存在一個數iii滿足比這個位置大的都是在第二個操作被取走的,前的都是第一個位置被取走的。并且最后肯定是第二個操作。如果ai≤ia_i\leq iai?≤i那么這個位置肯定是第一個操作被取走的,因為在此之前第二個操作不可能多過第一個操作。所以找到第一個ai>ia_i>iai?>i的位置然后判斷即可。
時間復雜度:O(nlog?n)O(n\log n)O(nlogn)
code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+10; int n,a[N]; int main() {scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);sort(a+1,a+1+n);reverse(a+1,a+1+n);for(int i=1;i<=n;i++)if(a[i+1]<i+1){if((a[i]-i)&1)return puts("First")&0;int r=i;while(a[r+1]==i)r++;if((r-i)&1)return puts("First")&0;return puts("Second")&0; }return 0; }AT2000 [AGC002F] Leftmost Ball【dp,組合數學】
https://www.luogu.com.cn/problem/AT2000
題目大意
有nnn種顏色,第iii種有kkk個,把所有排列中每種顏色的第一個染成同一種新的顏色(白色),求不同的排列數。
1≤n,k≤20001\leq n,k\leq 20001≤n,k≤2000
解題思路
相當于前綴顏色數小于等于前綴白色數,這個復雜度可以考慮平方的dpdpdp。
因為其實和第一個出現的顏色有關,我們可以只保留每種顏色的前兩個來dpdpdp,然后剩下的都插入到它們后面就好了,設fi,jf_{i,j}fi,j?表示現在有iii個白色,出現了jjj種顏色時的方案。
如果填白色就是直接fi?1,jf_{i-1,j}fi?1,j?,如果填顏色,我們可以在剩下的n?j+1n-j+1n?j+1個顏色中選出一個來,第二個填在目前的最前面,然后現在的空位是n?i?(j?1)×(k?1)?1n-i-(j-1)\times (k-1)-1n?i?(j?1)×(k?1)?1個再填k?2k-2k?2個就好了。
時間復雜度:O(n2)O(n^2)O(n2)
code
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=2100,P=1e9+7; ll n,k,inv[N*N],fac[N*N],f[N][N]; ll C(ll n,ll m) {return fac[n]*inv[m]%P*inv[n-m]%P;} signed main() {scanf("%lld%lld",&n,&k);if(k==1)return puts("1")&0;inv[0]=fac[0]=inv[1]=1;for(ll i=2;i<=n*k;i++)inv[i]=P-inv[P%i]*(P/i)%P;for(ll i=1;i<=n*k;i++)fac[i]=fac[i-1]*i%P,inv[i]=inv[i-1]*inv[i]%P;f[0][0]=1;for(ll i=1;i<=n;i++)for(ll j=0;j<=i;j++)f[i][j]=(f[i-1][j]+f[i][j-1]*(n-j+1)%P*C(n*k-i-(j-1)*(k-1)-1,k-2)%P)%P;printf("%lld\n",f[n][n]);return 0; }總結
以上是生活随笔為你收集整理的AGC002(D~F)【Kruskal重构树,博弈论,dp】的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: AT1981-[AGC001C]Shor
 - 下一篇: 手机的好处与坏处