标签:AGC003 Kruskal inv leq 操作 include ll dp
正题
AT1998 [AGC002D] Stamp Rally【Kruskal重构树,倍增】
https://www.luogu.com.cn/problem/AT1998
题目大意
给出\(n\)个点\(m\)条边的一张无向图,\(q\)次询问两个人分别从\(x,y\),要求总共经过\(z\)个点的情况下经过边的最大编号的最小值。
\(1\leq n,m,q\leq 10^5\)
解题思路
直接上\(Kruskal\)重构树然后预处理倍增数组和子树大小。
然后二分答案+倍增判断就好了,这样写是两个\(\log\)的,直接倍增一个\(\log\)也行但是比较麻烦。
时间复杂度:\(O(n\log^2n )\)
AT1999 [AGC002E] Candy Piles【博弈论】
https://www.luogu.com.cn/problem/AT1999
题目大意
\(n\)堆糖果,第\(i\)堆有\(a_i\)个,有如下操作
- 取走糖果最多的那堆
- 所有堆中各取走一个
\(1\leq n\leq 10^5,1\leq a_i\leq 10^9\)
解题思路
考虑如果现在操作的那个人一直用第一个操作会输那么它肯定会用第二个操作,而此时会转换胜负态,那么下一个人也会继续这么做,但是如果到最后一个且刚好是偶数那么使用第一个操作就更优。
所以肯定存在一个数\(i\)满足比这个位置大的都是在第二个操作被取走的,前的都是第一个位置被取走的。并且最后肯定是第二个操作。如果\(a_i\leq i\)那么这个位置肯定是第一个操作被取走的,因为在此之前第二个操作不可能多过第一个操作。所以找到第一个\(a_i>i\)的位置然后判断即可。
时间复杂度:\(O(n\log n)\)
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
题目大意
有\(n\)种颜色,第\(i\)种有\(k\)个,把所有排列中每种颜色的第一个染成同一种新的颜色(白色),求不同的排列数。
\(1\leq n,k\leq 2000\)
解题思路
相当于前缀颜色数小于等于前缀白色数,这个复杂度可以考虑平方的\(dp\)。
因为其实和第一个出现的颜色有关,我们可以只保留每种颜色的前两个来\(dp\),然后剩下的都插入到它们后面就好了,设\(f_{i,j}\)表示现在有\(i\)个白色,出现了\(j\)种颜色时的方案。
如果填白色就是直接\(f_{i-1,j}\),如果填颜色,我们可以在剩下的\(n-j+1\)个颜色中选出一个来,第二个填在目前的最前面,然后现在的空位是\(n-i-(j-1)\times (k-1)-1\)个再填\(k-2\)个就好了。
时间复杂度:\(O(n^2)\)
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;
}
标签:AGC003,Kruskal,inv,leq,操作,include,ll,dp 来源: https://www.cnblogs.com/QuantAsk/p/15457504.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。