zoukankan      html  css  js  c++  java
  • P7444「EZEC7」猜排列【dp】

    正题

    题目链接:https://www.luogu.com.cn/problem/P7444


    题目大意

    一个长度为\(n\)的排列,已知每个\(c_i\)表示那个排列中\(mex\)\(i\)的区间个数。求满足条件的排列个数

    \(1\leq n\leq 5\times 10^5,c_i\geq 0,\sum_{i=1}^nc_i=\frac{n(n+1)}{2}-1\)


    解题思路

    考虑一个朴素的\(dp\),设\(f_{i,l,r}\)表示加入了\(1\sim i\),然后最大区间是\([l,r]\)时的方案。

    那么每次插入一个数\(i\)的时候如果\(c_i=0\)那么它一定在目前的最大区间里,否则需要扩展到区间外,每次有往左或者往右扩展。

    不难发现对于\(1\sim i\)扩展到\(l\),那么\(r\)是固定的,所以我们可以直接用\(f_{i,l}\)来表示状态,但是这样还是\(O(n^2)\)的,其实状态数比较少的,因为对于一个\(i\)来说需要扩展的\(a_i\)都是一些倍数形的。

    其实总状态数不会超过\(\sum_{i=1}^n\sqrt{a_i}\),因为上限很难到,所以用个\(vector\)记录一下状态就能够过了


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define ll long long
    using namespace std;
    const ll N=5e5+10,P=998244353;
    ll n,a[N],f[2][N],ed[2][N],vis[N];
    vector<int> v[2]; 
    signed main()
    {
    	scanf("%lld",&n);
    	for(ll i=0;i<n;i++)
    		scanf("%lld",&a[i]);
    	ll Ans=0,s=0;
    	for(ll i=1;i<=n;i++){
    		ll l=i-1,r=n-i;
    		if(l*(l+1)+r*(r+1)==a[0]*2)
    			s=i,Ans++;
    	}
    	if(!Ans)return puts("0")&0;
    	f[0][s]=1;ed[0][s]=s;v[0].push_back(s);
    	for(ll i=1;i<n-1;i++){
    		v[i&1].clear();
    		for(ll p=0;p<v[~i&1].size();p++){
    			ll l=v[~i&1][p],r=ed[~i&1][l];
    			if(vis[l]==i)continue;vis[l]=i;
    			if(!a[i]){
    				if(r-l-i<0)continue;
    				(f[i&1][l]+=f[~i&1][l]*(r-l-i+1)%P)%=P;
    				ed[i&1][l]=r;v[i&1].push_back(l);
    			}
    			else{
    				ll lk=l,rk=n-r+1;
    				if(a[i]%lk==0){
    					ll nr=r+a[i]/lk;
    					(f[i&1][l]+=f[~i&1][l])%=P;
    					ed[i&1][l]=nr;v[i&1].push_back(l);
    				} 
    				if(a[i]%rk==0){
    					ll nl=l-a[i]/rk;
    					(f[i&1][nl]+=f[~i&1][l])%=P;
    					ed[i&1][nl]=r;v[i&1].push_back(nl);
    				}
    			}
    		}
    		for(ll p=0;p<v[~i&1].size();p++)
    			f[~i&1][v[~i&1][p]]=0;
    	}
    	ll ans=0;
    	for(ll i=1;i<=n;i++)
    		(ans+=f[(n-2)&1][i])%=P;
    	printf("%lld\n",ans*Ans%P);
    	return 0;
    }
    
  • 相关阅读:
    【PHP】新浪、淘宝的地区 API调用
    wdcp/wdlinux 常用工具及命令集
    wdcp/wdlinux一键包的php5.3版本添加Zend.so 和Soap.so
    WDCP一些常用的一健安装包可选安装组件
    WDCP安装memcached
    WDCP控制面板安装卸载
    linux添加环境变量
    Linux常用命令大全
    [译]git commit
    [译]git add
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14578729.html
Copyright © 2011-2022 走看看