首页 > 其他分享 >Codeforces Gym 103439D - LIS Counting(猜结论+状压)

Codeforces Gym 103439D - LIS Counting(猜结论+状压)

时间:2023-05-01 16:22:41浏览次数:33  
标签:return cur int 103439D Gym 状压 text LIS 数列

一道需要一些猜结论技巧的中档题。

首先突破口在于排列长度恰好等于不是额外输入的某个数 \(k\) 而是 LDS 与 LIS 的乘积,这显然启示我们去找一些性质。根据 dilworth 定理,最长反链等于最小链覆盖,故 LIS 的长度,就是最少需要的递减数列的个数使得每个元素被覆盖至少一次,而每个递减数列长度不超过 \(m\),因此 \(n\) 个递减数列长度不超过 \(nm\)。换句话,\(nm\) 是 \(\text{LIS}=n,\text{LDS}=m\) 的排列长度的最小值。

先考虑怎么计算 \(\text{LIS}=n,\text{LDS}=m,\text{len}=nm\) 的排列个数。大胆猜一个结论:对于符合要求的排列,将其划分为 \(n\) 个递减数列的方案是唯一的。并且如果我们假设 \(a_{i,j}\) 为第 \(i\) 个递减数列中第 \(j\) 个元素在排列中的位置,\(p_{i,j}\) 为第 \(i\) 个递减数列中第 \(j\) 个元素的值,那么有:

  • \(a_{i,j}\le a_{i,j+1},a_{i,j}\le a_{i+1,j}\)
  • \(p_{i,j}\ge p_{i,j+1},p_{i,j}\le p_{i+1,j}\)。

发现 \(a,p\) 的安排是两个完全不相干的子问题,因此分别求解方案数然后乘起来就是排列总数。而两者方案数显然是完全相同的,写个阶乘的暴力验证一下也会发现答案确实是完全平方数。因此只用知道怎么计算符合条件的 \(a\) 的个数即可。而这个过程显然相当于每次新填一个数的时候,已经填的数和没填的数的分界线是一条从左下角到右上角,且只能向右或向上的折线。这样的折线最多只有 \(\dbinom{n+m}{n}\) 种,当 \(nm\le 100\) 时该值大概最多是 \(2\times 10^5\) 级别的,因此直接写个状压 dp 记录折线信息即可。

知道怎么算总数以后,计算 \(f(pos,val)\) 的部分是 trivial 的——枚举这个位置上的值是第 \(x\) 个下降序列的第 \(y\) 个元素,那么对 \(a,p\) 的限制相当于强制要求 \(a_{x,y}=v\),预处理 \(F_{x,y,v}\) 表示强制令 \(a_{x,y}=v\) 的符合要求的矩阵的方案数,这个可以直接枚举左边部分的折线然后 DP 算一下左右部分的方案数乘起来得到。

const int MAXN=100;
const int MAXC=184756;
int n,m,mod,rv,f[MAXN+5][MAXN+5][MAXN+5];
int calc(int x,int y,int num){
	if(rv)return f[y][x][num];
	else return f[x][y][num];
}
bool check(vector<int>v){
	for(int i=1;i<v.size();i++)if(v[i]>v[i-1])return 0;
	return 1;
}
map<vector<int>,int>id;
vector<int>cur,v[MAXC+5];
int idcnt=0,dp[MAXC+5];
void dfs(int x,int lst){
	if(x==n+1){
		reverse(cur.begin(),cur.end());
		id[cur]=++idcnt;v[idcnt]=cur;
		reverse(cur.begin(),cur.end());return;
	}
	for(int i=lst;i<=m;i++)cur.pb(i),dfs(x+1,i),cur.ppb();
}
int main(){
	scanf("%d%d%d",&n,&m,&mod);
	if(n>m)swap(n,m),rv=1;
	dfs(1,0);dp[1]=1;
	for(int i=1;i<=idcnt;i++){
		vector<int>cur=v[i];
		for(int j=0;j<n;j++)if(cur[j]<m){
			cur[j]++;
			if(check(cur)){
				int nid=id[cur];
				dp[nid]=(dp[nid]+dp[i])%mod;
			}
			cur[j]--;
		}
	}
	for(int i=1;i<=idcnt;i++){
		vector<int>cur=v[i];
		for(int j=0;j<n;j++)if(cur[j]<m){
			cur[j]++;
			if(check(cur)){
				int nid=id[cur],sum=0;for(int k=0;k<n;k++)sum+=cur[k];
				vector<int>rst(n);
				for(int k=0;k<n;k++)rst[k]=m-cur[n-1-k];
				f[j+1][cur[j]][sum]=(f[j+1][cur[j]][sum]+1ll*dp[i]*dp[id[rst]])%mod;
			}cur[j]--;
		}
	}
	if(rv)swap(n,m);
	for(int i=1;i<=n*m;i++)for(int j=1;j<=n*m;j++){
		int res=0;
		for(int x=1;x<=n;x++)for(int y=1;y<=m;y++)
			res=(res+1ll*calc(x,y,i)*calc(x,m-y+1,j))%mod;
		printf("%d%c",res," \n"[j==n*m]);
	}
	return 0;
}

标签:return,cur,int,103439D,Gym,状压,text,LIS,数列
From: https://www.cnblogs.com/tzcwk/p/Gym-103439D.html

相关文章

  • Codeforces 1804H - Code Lock(状压 dp)
    对于一种排列方案,答案显然等于相邻字符在环上对应的劣弧长度之和。然后其实你可能会想到很多状压/折半搜索方法,包括但不限于枚举一半的信息然后折半搜后一半,但稍加思考会发现这些方案都避不开记录元素之间的相对顺序,而但凡涉及到这一点,复杂度都是阶乘起步。因此我们只能另辟蹊......
  • GYM104081 部分题解
    比赛链接:https://codeforces.com/gym/104081目前就做了8题,里面还有4个水题……水题:ACEG,模拟题意即可,C和E有一些细节。不想写题解了F首先目标是如何将这9个数分组,由于答案一定存在,考虑随机化,固定\(a_1\inS_1\),然后随机一个\(a_i\inS_1\),异或得到\(S_1\)的另一......
  • 状压DP
    状压DP状压DP是动态规划的一种,通过将状态压缩为整数来达到优化转移的目的。例题售货员的难题洛谷1171#include<bits/stdc++.h>usingnamespacestd;intn,i,j,k,min1,a[25][25],f[1050000][25];intmain(){ cin>>n; for(i=1;i<=n;i++) for(j=1;j<=n;j++) cin>......
  • HDU 4628 Pieces (状压DP)
    题目地址:HDU4628这题没想到怎么快速枚举子状态。。。看了题解才知道的。用for(state=i;state>0;state=(state-1)&i)就可以了。这题的具体做法是先预处理出所有的状态是不是回文串,然后就是普通的DP了。代码如下:#include<iostream>#include<string.h>#include<math.h>......
  • 【容斥、状压dp】主旋律 题解
    【清华集训2014】主旋律题解神秘题。题目简述给你一个有向图\(G=(V,E)\)。求有多少\(E\)的子集\(E'\)使得新图\(G'=(V,E')\)是强连通图。强连通图的定义是任意两点\(u,v\)均存在\(u\tov,v\tou\)的路径。\(n\leq15,m\leqn\times(n-1)\)。解题思路......
  • 状压DP
    [acwing]291.蒙德里安的梦想/* 横放的方案数就等于总方案数,因为横着放完后,再竖着放是唯一的 dp[i][j]表示第i列状态为j的方案数 状态为j是指:各行用0或1表示摆放状态 :若某行为0,表示竖放或由前一列伸出 :若某行为1,表示横放并向后一列伸出 ......
  • Codeforces Gym 103931F - Forest of Magic(时间轴分块+线段树合并)
    一个巨烦的时间轴分块做法,有点类似于P2137Gty的妹子树先考虑静态的情况。看上去就一脸线段树合并对吧?一次修改的操作对一个点\(x\)贡献可以写成\(k·dep_x+b\)的形式,开两棵线段树合并维护一次项和零次项系数即可。由于静态问题可做,因此考虑时间轴分块。设阈值\(B\),每\(B......
  • Gym104076L Tree Distance
    Gym104076LTreeDistance题目链接。\(\text{difficulty}={4,2.5}\)。\(\text{tags}=点分治,扫描线\)。没见过确实想不到。由于查询是区间对区间,分块等数据结构并不好......
  • bnuoj 12976 Collecting Gold 状压dp
    http://www.bnuoj.com/problem_show.php?pid=12976状态转移方程:dp[s|1<<j][j]=min(dp[s|1<<j][j],dp[s][i]+dis(i,j));code:#include<iostream>#include<stdio.h>#in......
  • Magic Potion Gym - 101981I
    有n个人,m个怪兽,k瓶药水,现在依次给出每个人可以杀的怪物的数量t以及怪物的编号,每个人只能杀他能杀的一个怪物,但可以领取一瓶药水复活再杀一个(只能领取一次),问最多能......