2019 年百度之星·程序设计大赛 - 初赛三—min

题目链接->->->min

分析:

min(api,api+1)≤min(api+1,api+2)

一开始博主根据上述条件胡了好几个假结论.....

上述条件可以转化为条件T:把a中数加入到一个空数组中,从前往后,如果当前加入的数是当前所剩数中最小的数,那么加入的下一个数可以任意,否则加入的下一个数必须是所剩数中的最小的数,或者换句话来说,不能够连续加入的两个数都不是当前剩余的最小数。这样做我们可以得到一个数组,注意其中的数是带标号的。

那么这样可以很容易想到dp,但是由于有后效性被ka掉了。

逆向考虑:从小到大加入每一个数。假设当前要加入数x,那么对于当前的数列来说,x只能被加在数列末尾,或者满足条件的中间位置。这个满足条件是什么?就是对于当前数列中的相邻两个数,如果他们都满足根据我上述所说的条件T中的都是当前剩余的数中的最小值(依据条件T中的构造方式),那么数x就可以被插入到这两个数之间。

那么我们可以用dp维护当前有i个可插入位置的方案数。

博主的思维非常诡异,所以选取了上述内容作为博主自己对这道题的看法,而且其中的分析过程有点......

#include
#define ll long long
using namespace std;
const int N=1e3+10;
const ll mod=998244353;
int fac[N],inv[N],a[N],b[N],f[2][N];
int T,n,x;
int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
int mul(int x,int y){return (ll)x*y%mod;}
void init(){
	fac[0]=1;
	for (int i=1;i=1) b[++cnt]=a[i];
		for (int i=0;i<=n;i++) f[1][i]=f[0][i]=0;
		f[1][b[1]]=fac[b[1]];
		int s=b[1];
//		for (int i=1;i<=n;i++) printf("%d\n",b[i]);
		for (int i=2;i<=cnt;i++) {
			for (int j=0;j<=s+b[i];j++) f[i&1][j]=0;  
			for (int j=0;j<=b[i];j++) 
			 for (int k=max(2*j-b[i],0);k<=s;k++) 
			 if (f[i&1^1][k])
			  f[i&1][k-j+b[i]-j]=add(f[i&1][k+b[i]-2*j],mul(f[i&1^1][k],mul(mul(fac[b[i]-j],fac[j]),mul(C(b[i],j),C(k,j)))));  
			s+=b[i];  
//			for (int j=0;j<=s;j++) printf("%d\n",f[i&1][j]);
		}
		int ans=0;
		for (int i=0;i<=n;i++) ans=add(ans,f[cnt&1][i]);
		printf("%d\n",ans);
	}
}

 

你可能感兴趣的:(2019 年百度之星·程序设计大赛 - 初赛三—min)