首页 > 其他分享 >ARC162E

ARC162E

时间:2023-08-13 20:13:45浏览次数:36  
标签:DJ ARC162E int long MAXN dp MOD

ARC162E

A

简单分类讨论即可

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e3+5;
int T;
int n;
int P[MAXN];
int main()
{
	// freopen("date.in","r",stdin);
	// freopen("date.out","w",stdout);
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&P[i]);
		}
		int Res=0;
		for(int i=1;i<=n;i++)
		{
			bool f=1;
			for(int j=i+1;j<=n;j++)
			{
				if(P[j]<P[i])
				{
					f=0;
				}
			}
			Res+=f;
		}
		printf("%d\n",Res);

	}
}

B

一个初步的想法是将\(1-n\)每个数依次排好序,唯一可能出现的问题是目前想排的数被抵到末尾了,这里我们只需要把它调整\(n-1\)的位置即可,只有当剩余只有两个数出现这种情况时无解

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e3+5;
int n;
int P[MAXN];
int Tmp[MAXN];
int main()
{
	// freopen("date.in","r",stdin);
	// freopen("date.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&P[i]);
	}
	vector<pair<int,int>>Opra;
	for(int i=1;i<n;i++)
	{
		
		int Pos;
		if(P[i]==i)
		{
			continue;
		}
		for(int j=i;j<=n;j++)
		{
			if(P[j]==i)
			{
				Pos=j;
				break;
			}
		}
		if(Pos==n)
		{
			if((n-i+1)<=2)
			{
				printf("No");
				return 0;
			}
			Opra.push_back(make_pair(n-1,n-3));
			Pos=n-1;
			int gk=P[n-2];
			P[n-2]=P[n-1];
			P[n-1]=P[n];
			P[n]=gk;
		}
		Opra.push_back(make_pair(Pos,i-1));
		for(int j=i;j<=n;j++)
		{
			Tmp[j]=P[j];
		}
		P[i]=Tmp[Pos];
		P[i+1]=Tmp[Pos+1];
		int Poi=i;
		for(int j=i+2;j<=n;j++)
		{
			if(Poi==Pos)
			{
				Poi+=2;
			}
			P[j]=Tmp[Poi];
			++Poi;
		}
	}
	printf("Yes\n");
	printf("%ld\n",Opra.size());
	for(int i=0;i<Opra.size();i++)
	{
		printf("%d %d\n",Opra[i].first,Opra[i].second);
	}
}

C

很zz的博弈

很明显\(B\)只会填\(k\),填了\(u\)之后\(u\)的祖先都不可能赢

对于\(A\),她只能走第一步赢,因为\(B\)可以根据\(A\)选的点来破坏\(A\)想让\(u\)赢的意图

所以直接check一下\(A\)走一步能不能赢即可

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1005;
int T;
int n,k;
int x;
int A[MAXN];
vector<int>g[MAXN];
int Vis[MAXN];
int Cnt=0;
void find(int x,int f)
{
	if(A[x]!=-1)
	{
		Vis[A[x]]=1;
	}
	else
	{
		++Cnt;
	}
	for(int i=0;i<g[x].size();i++)
	{
		int v=g[x][i];
		if(v==f)
		{
			continue;
		}
		find(v,x);
	}
}
bool found=0;
void dfs(int x,int f)
{
	for(int i=0;i<g[x].size();i++)
	{
		int v=g[x][i];
		if(v==f)
		{
			continue;
		}
		dfs(v,x);
	}
	for(int i=0;i<=n;i++)
	{
		Vis[i]=0;
	}
	Cnt=0;
	find(x,f);
	int Mex;
	for(int i=0;i<=n;i++)
	{
		if(!Vis[i])
		{
			Mex=i;
			break;
		}
	}
	if(Mex==k&&((!Cnt)||(Cnt==1)))
	{
		found=1;
	}
	if(Cnt==1)
	{
		//printf("%d???\n",Mex);
		Vis[Mex]=1;
		for(int i=0;i<=n;i++)
		{
			if(!Vis[i])
			{
				Mex=i;
				break;
			}
		}
		if(Mex==k)
		{
			//printf("%deee???\n",x);
			found=1;
		}
	}
}
int main()
{
	// freopen("date.in","r",stdin);
	// freopen("date.out","w",stdout);
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d %d",&n,&k);
		for(int i=1;i<=n;i++)
		{
			g[i].clear();
		}
		for(int i=2;i<=n;i++)
		{
			scanf("%d",&x);
			g[x].push_back(i);
		}
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&A[i]);
		}
		found=0;
		dfs(1,0);
		if(found)
		{
			printf("Alice\n");
		}
		else
		{
			printf("Bob\n");
		}
	}
}	

E

乍一看都不知道这个题在说些什么

仔细想想就可以发现设\(d_i\)为\(i\)出现的次数

我们要保证\(d_i\le A_i\)并且满足填入第\(i\)位的数\(j\)满足\(d_j\le A_i\)

这个\(d_i\le A_i\),经典\(dp\)

而对于后面的条件,我们可以按填的\(d_i\)从大到小\(dp\),这样就可以得到哪些位置能填以及哪些值能用

具体的设\(dp_{i,j,k}\)表示考虑了出现次数\(\ge i\)的,填了\(j\)种数,填了\(k\)个位置的方案数

转移直接枚举下一次填了\(t\)种数即可,时间复杂度因为\(j,i\le\dfrac{n}{i}\),精细实现是\(O(n^3)\)的,多个\(log\)好像会\(T\)

// LUOGU_RID: 120706268
#include<bits/stdc++.h>
using namespace std;
const int MAXN=505;
const int MOD=998244353;
int n;
int a[MAXN];
int dp[MAXN][MAXN][MAXN];
int C[MAXN][MAXN];
int fac[MAXN];
int inv_fac[MAXN];
int Cp[MAXN];
int Pow(int a,int b,int p)
{
	int res=1;
	int base=a;
	while(b)
	{
		if(b&1)
		{
			res=((long long)res*base)%p;
		}
		base=((long long)base*base)%p;
		b>>=1;
	}
	return res;
}
int inv(int a,int p)
{
	return Pow(a,p-2,p);
}
int main()
{
	// freopen("date.in","r",stdin);
	// freopen("date.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	for(int i=0;i<=n;i++)
	{
		Cp[i]=0;
		for(int j=1;j<=n;j++)
		{
			if(a[j]>=i)
			{
				Cp[i]++;
			}
		}
	}
	C[0][0]=1;
	fac[0]=1;
	for(int i=1;i<=n;i++)
	{
		C[i][0]=1;
		fac[i]=((long long)fac[i-1]*i)%MOD;
		for(int j=1;j<=n;j++)
		{
			C[i][j]=((long long)C[i-1][j]+C[i-1][j-1])%MOD;
		}
	}
	inv_fac[n]=inv(fac[n],MOD);
	for(int i=n-1;i>=0;i--)
	{
		inv_fac[i]=((long long)inv_fac[i+1]*(i+1))%MOD;
	}
	dp[n+1][0][0]=1;
	for(int i=n+1;i>=1;i--)
	{
		int P=Cp[i-1];
		for(int j=0;j<=n&&j<=P&&(i*j<=n);j++)
		{
			for(int k=0;k<=P;k++)
			{
				if(!dp[i][j][k])
				{
					continue;
				}
				int Pw=1;
				for(int t=1;t+j<=n&&k+(t*(i-1))<=P&&t<=P&&(P-k-t*(i-1))>=0;t++)
				{
					Pw=((long long)Pw*inv_fac[i-1])%MOD;
					int DJ=dp[i][j][k];
					DJ=((long long)DJ*C[P-j][t])%MOD;
					DJ=((long long)DJ*fac[P-k])%MOD;
					DJ=((long long)DJ*Pw)%MOD;
					DJ=((long long)DJ*inv_fac[P-k-t*(i-1)])%MOD;
					dp[i-1][t+j][k+(t*(i-1))]=((long long)dp[i-1][t+j][k+(t*(i-1))]+DJ)%MOD;
				}
				dp[i-1][j][k]=((long long)dp[i-1][j][k]+dp[i][j][k])%MOD;
			}
		}		
	}

	printf("%d",dp[0][n][n]);
}

标签:DJ,ARC162E,int,long,MAXN,dp,MOD
From: https://www.cnblogs.com/kid-magic/p/17627139.html

相关文章

  • ARC162E Strange Constraints
    题意给定长度为\(n\)的序列\(A\),求序列\(B\)的个数模\(998244353\),满足以下条件:值域\([1,n]\)。\(i\)的个数不超过\(A_i\)。\(B_i\)的个数不超过\(A_i\)。\(1\len\le500\)。题解发现按照某种顺序去构造是困难的,考虑倒过来,枚举出现次数。如果某个类出现次......