首页 > 其他分享 >染色数组

染色数组

时间:2023-04-05 09:04:12浏览次数:32  
标签:le int 染色 元素 add ge 数组 mod

定义集合\(S\)由同时满足以下条件的\(x\)构成:

  • \([1,x)\)中\(\le a_{x}\)的元素 和 \((x,n]\)中\(\ge a_{x}\)的元素 构成递增子序列
  • \([1,x)\)中\(\ge a_{x}\)的元素 和 \((x,n]\)中\(\le a_{x}\)的元素 构成递减子序列

性质1:\(a\)为完美数组当且仅当\(S\ne \empty\)

必要性:注意\(x\in S\)是\(x\)可以染成红色和绿色的必要条件

充分性:任取\(x\in S\),将条件中第\(1\)类元素染成红色,其余染成绿色即可

性质2:若\(x\in S\),则\(x+1\in S\iff \forall i\in [1,x),a_{i}\not\in [a_{x},a_{y}]\cup [a_{y},a_{x}]\)

性质3:记\(\begin{cases}l=\min_{x\in S}x\\r=\max_{x\in S}x\end{cases}\),则\(S=[l,r]\cap Z\)且满足以下条件之一

  • \(l+1=r\)且\(a_{l}=a_{r}\)
  • \(a_{l}<a_{l+1}<...<a_{r}\)或\(a_{l}>a_{l+1}>...>a_{r}\)

(证明可以自行分类讨论得到)

为了方便,以下均假设为第\(2\)种情况,第\(1\)种情况是类似的


根据性质\(3\),在\(r\)处统计方案数,即要求\(r+1\not\in S\),这可以用性质\(2\)判定

注意到对于\(a_{[1,r)}\),恰存在一种染色方式使得红色的结尾\(<a_{r}\)且绿色的结尾\(>a_{r}\)

定义\(f_{i,x,y}\)表示前\(i\)个位置中两序列结尾分别为\(x,y\)的方案数,转移易优化至\(O(nm^{2})\),后缀类似

枚举\(r,a_{r}\)和\(a_{r+1}\)后,即求形如\(\sum_{x\le x_{0}}\sum_{y\ge y_{0}}f_{i,x,y}\),预处理即可,时间复杂度为\(O(tnm^{2})\)


性质4:得分最大的染色方案形如

  • \([1,r)\)中\(\le a_{r}\)的元素 和 \((r,n]\)中\(\ge a_{r}\)的元素 染成红色
  • \([1,r)\)中\(\ge a_{r}\)的元素 和 \((r,n]\)中\(\le a_{r}\)的元素 染成绿色
  • \(a_{r}\)的颜色取染红色或绿色中的较大值

此时,将贡献拆开,得分分为以下几部分:

  • \(a_{[1,r)}\)中,用\(g/g0/g1_{i,x,y}\)表示……的得分和、红色数和 和 绿色数和 即可

  • \(a_{r}\)中,用\(f'_{i,z,x,y}\)表示在\(f_{i,x,y}\)的基础上红色有\(z\)个的方案数即可

  • \(a_{(r,n]}\)中,其内部无贡献,仅与\(a_{[1,r)}\)之间有贡献

    以染成红色的\(a_{i}\)为例,即统计\(a_{[1,r)}\)中\(>a_{i}\)的元素个数,枚举\(a_{i}\)即可

时间复杂度为\(O(tn^{2}m^{2}+tnm^{3})\),大概不是标算,但卡卡常应该能过(雾
(以下代码并没有卡常,正确性仅保证过大样例)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=55,M=205,mod=998244353;
int t,n,m,n0,ans1,ans2,a[N];
int fs[N][M][M],Fp[N][N][M][M],gp0[N][M][M],gp1[N][M][M],gs[N][M][M];
int add(int x,int y){
	x+=y;
	return (x<mod ? x : x-mod);
}
struct Data{
	int f,g,g0,g1;
	Data upd0(int x){
		return Data{f,(int)((g+(ll)x*g0)%mod),g0,add(f,g1)};
	}
	Data upd1(int x){
		return Data{f,(int)((g+(ll)(m-x+1)*g1)%mod),add(f,g0),g1};
	}
}fp[N][M][M];
Data add(Data x,Data y){
	return Data{add(x.f,y.f),add(x.g,y.g),add(x.g0,y.g0),add(x.g1,y.g1)};
}
Data dec(Data x,Data y){
	return Data{add(x.f,mod-y.f),add(x.g,mod-y.g),add(x.g0,mod-y.g0),add(x.g1,mod-y.g1)};
}
void get_sum(Data a[M][M]){
	for(int i=0;i<=m;i++)
		for(int j=m+1;j>i;j--){
			if (i)a[i][j]=add(a[i][j],a[i-1][j]);
			if (j<=m)a[i][j]=add(a[i][j],a[i][j+1]);
			if ((i)&&(j<=m))a[i][j]=dec(a[i][j],a[i-1][j+1]);
		}
}
void get_fp(){
	memset(fp,0,sizeof(fp));
	for(int x=0;x<=m;x++)
		for(int y=x+1;y<=m+1;y++)fp[0][x][y]=Data{1,0,0,0};
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if ((i<=n0)&&(a[i]!=j))continue;
			for(int x=0;x<j;x++){
				fp[i][x][j]=add(fp[i][x][j],fp[i-1][x][j+1].upd0(j));
				if (x)fp[i][x][j]=dec(fp[i][x][j],fp[i-1][x-1][j+1].upd0(j));
			}
			for(int y=j+1;y<=m+1;y++){
				fp[i][j][y]=add(fp[i][j][y],fp[i-1][j-1][y].upd1(j));
				if (y<=m)fp[i][j][y]=dec(fp[i][j][y],fp[i-1][j-1][y+1].upd1(j));
			}
		}
		get_sum(fp[i]);
	}
}
void get_sum(int a[M][M]){
	for(int i=0;i<=m;i++)
		for(int j=m+1;j>i;j--){
			if (i)a[i][j]=add(a[i][j],a[i-1][j]);
			if (j<=m)a[i][j]=add(a[i][j],a[i][j+1]);
			if ((i)&&(j<=m))a[i][j]=add(a[i][j],mod-a[i-1][j+1]);
		}
}
void get_fs(){
	memset(fs,0,sizeof(fs));
	for(int x=0;x<=m;x++)
		for(int y=x+1;y<=m+1;y++)fs[n+1][x][y]=1;
	for(int i=n;i;i--){
		for(int j=1;j<=m;j++){
			if ((i<=n0)&&(a[i]!=j))continue;
			for(int x=0;x<j;x++){
				fs[i][x][j]=add(fs[i][x][j],fs[i+1][x][j+1]);
				if (x)fs[i][x][j]=add(fs[i][x][j],mod-fs[i+1][x-1][j+1]);
			}
			for(int y=j+1;y<=m+1;y++){
				fs[i][j][y]=add(fs[i][j][y],fs[i+1][j-1][y]);
				if (y<=m)fs[i][j][y]=add(fs[i][j][y],mod-fs[i+1][j-1][y+1]);
			}
		}
		get_sum(fs[i]);
	}
}
void get_Fp(){
	memset(Fp,0,sizeof(Fp));
	for(int x=0;x<=m;x++)
		for(int y=x+1;y<=m+1;y++)Fp[0][0][x][y]=1; 
	for(int i=1;i<=n;i++)
		for(int z=0;z<=i;z++){
			for(int j=1;j<=m;j++){
				if ((i<=n0)&&(a[i]!=j))continue;
				for(int x=0;x<j;x++){
					Fp[i][z][x][j]=add(Fp[i][z][x][j],Fp[i-1][z][x][j+1]);
					if (x)Fp[i][z][x][j]=add(Fp[i][z][x][j],mod-Fp[i-1][z][x-1][j+1]);
				}
				if (z){
					for(int y=j+1;y<=m+1;y++){
						Fp[i][z][j][y]=add(Fp[i][z][j][y],Fp[i-1][z-1][j-1][y]);
						if (y<=m)Fp[i][z][j][y]=add(Fp[i][z][j][y],mod-Fp[i-1][z-1][j-1][y+1]);
					}
				}
			}
			get_sum(Fp[i][z]);
		}
}
void get_gp(int w){
	memset(gp0,0,sizeof(gp0));
	memset(gp1,0,sizeof(gp1));
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if ((i<=n0)&&(a[i]!=j))continue;
			for(int x=0;x<j;x++){
				gp0[i][x][j]=add(gp0[i][x][j],gp0[i-1][x][j+1]);
				gp1[i][x][j]=add(gp1[i][x][j],gp1[i-1][x][j+1]);
				if (x){
					gp0[i][x][j]=add(gp0[i][x][j],mod-gp0[i-1][x-1][j+1]);
					gp1[i][x][j]=add(gp1[i][x][j],mod-gp1[i-1][x-1][j+1]);
				}
			}
			for(int y=j+1;y<=m+1;y++){
				gp0[i][j][y]=add(gp0[i][j][y],gp0[i-1][j-1][y]);
				gp1[i][j][y]=add(gp1[i][j][y],gp1[i-1][j-1][y]);
				if (y<=m){
					gp0[i][j][y]=add(gp0[i][j][y],mod-gp0[i-1][j-1][y+1]);
					gp1[i][j][y]=add(gp1[i][j][y],mod-gp1[i-1][j-1][y+1]);
				}
			}
			if (j<w){
				for(int x=0;x<j;x++){
					gp0[i][x][j]=(gp0[i][x][j]+(ll)w*fp[i-1][x][j+1].f)%mod;
					if (x)gp0[i][x][j]=(gp0[i][x][j]+(ll)w*(mod-fp[i-1][x-1][j+1].f))%mod;
				}
				for(int y=j+1;y<=m+1;y++){
					gp0[i][j][y]=(gp0[i][j][y]+(ll)w*fp[i-1][j-1][y].f)%mod;
					if (y<=m)gp0[i][j][y]=(gp0[i][j][y]+(ll)w*(mod-fp[i-1][j-1][y+1].f))%mod;
				}
			}
			if (j>w){
				for(int x=0;x<j;x++){
					gp1[i][x][j]=(gp1[i][x][j]+(ll)(m-w+1)*fp[i-1][x][j+1].f)%mod;
					if (x)gp1[i][x][j]=(gp1[i][x][j]+(ll)(m-w+1)*(mod-fp[i-1][x-1][j+1].f))%mod;
				}
				for(int y=j+1;y<=m+1;y++){
					gp1[i][j][y]=(gp1[i][j][y]+(ll)(m-w+1)*fp[i-1][j-1][y].f)%mod;
					if (y<=m)gp1[i][j][y]=(gp1[i][j][y]+(ll)(m-w+1)*(mod-fp[i-1][j-1][y+1].f))%mod;
				}
			}
		}
		get_sum(gp0[i]),get_sum(gp1[i]);
	}
}
void get_gs(int w){
	memset(gs,0,sizeof(gs));
	for(int i=n;i;i--){
		for(int j=1;j<=m;j++){
			if ((i<=n0)&&(a[i]!=j))continue;
			for(int x=0;x<j;x++){
				gs[i][x][j]=add(gs[i][x][j],gs[i+1][x][j+1]);
				if (x)gs[i][x][j]=add(gs[i][x][j],mod-gs[i+1][x-1][j+1]);
			}
			for(int y=j+1;y<=m+1;y++){
				gs[i][j][y]=add(gs[i][j][y],gs[i+1][j-1][y]);
				if (y<=m)gs[i][j][y]=add(gs[i][j][y],mod-gs[i+1][j-1][y+1]);
			}
			if (j==w){
				for(int x=0;x<j;x++){
					gs[i][x][j]=add(gs[i][x][j],fs[i+1][x][j+1]);
					if (x)gs[i][x][j]=add(gs[i][x][j],mod-fs[i+1][x-1][j+1]);
				}
				for(int y=j+1;y<=m+1;y++){
					gs[i][j][y]=add(gs[i][j][y],fs[i+1][j-1][y]);
					if (y<=m)gs[i][j][y]=add(gs[i][j][y],mod-fs[i+1][j-1][y+1]);
				}
			}
		}
		get_sum(gs[i]);
	}
}
int main(){
	scanf("%d",&t);
	while (t--){
		scanf("%d%d%d",&n,&m,&n0);
		for(int i=1;i<=n0;i++)scanf("%d",&a[i]);
		ans1=ans2=0;
		get_fp(),get_fs(),get_Fp();
		for(int i=1;i<n;i++)
			for(int j=1;j<=m;j++){
				if ((i<=n0)&&(a[i]!=j)||(i<n0)&&(a[i+1]!=j))continue;
				int s=fs[i+2][j-1][j+1];
				ans1=(ans1+(ll)fp[i-1][j-1][j+1].f*s)%mod;
				ans2=(ans2+(ll)fp[i-1][j-1][j+1].g*s)%mod;
				for(int z=0;z<i;z++)ans2=(ans2+(ll)(z*j+(i-z-1)*(m-j+1))*Fp[i-1][z][j-1][j+1]%mod*s)%mod;
			}
		for(int i=1;i<=m;i++){
			if ((n<=n0)&&(a[n]!=i))continue;
			ans1=add(ans1,fp[n-1][i-1][i+1].f);
			ans2=add(ans2,fp[n-1][i-1][i+1].g);
			for(int z=0;z<n;z++)ans2=(ans2+(ll)max(z*i,(n-z-1)*(m-i+1))*Fp[n-1][z][i-1][i+1])%mod;
		}
		for(int i=1;i<n;i++)
			for(int x=1;x<=m;x++){
				if ((i<=n0)&&(a[i]!=x))continue;
				for(int y=1;y<=m;y++){
					if ((i<n0)&&(a[i+1]!=y))continue;
					if (y<x){
						int s=fs[i+2][y-1][x+1];
						Data o=dec(fp[i-1][x-1][x+1],fp[i-1][y-1][x+1]);
						ans1=(ans1+(ll)o.f*s)%mod,ans2=(ans2+(ll)o.g*s)%mod;
						for(int z=0;z<i;z++)ans2=(ans2+(ll)max(z*x,(i-z-1)*(m-x+1))*(Fp[i-1][z][x-1][x+1]+mod-Fp[i-1][z][y-1][x+1])%mod*s)%mod;
					}
					if (y>x){
						int s=fs[i+2][x-1][y+1];
						Data o=dec(fp[i-1][x-1][x+1],fp[i-1][x-1][y+1]);
						ans1=(ans1+(ll)o.f*s)%mod,ans2=(ans2+(ll)o.g*s)%mod;
						for(int z=0;z<i;z++)ans2=(ans2+(ll)max(z*x,(i-z-1)*(m-x+1))*(Fp[i-1][z][x-1][x+1]+mod-Fp[i-1][z][x-1][y+1])%mod*s)%mod;
					}
				}
			}
		for(int w=1;w<=n;w++){
			get_gp(w),get_gs(w);
			for(int i=1;i<n;i++)
				for(int j=1;j<=m;j++){
					if ((i<=n0)&&(a[i]!=j)||(i<n0)&&(a[i+1]!=j))continue;
					ans2=(ans2+(ll)(w<j ? (ll)gp0[i-1][j-1][j+1] : gp1[i-1][j-1][j+1])*gs[i+2][j-1][j+1])%mod;
				}
			for(int i=1;i<n;i++)
				for(int x=1;x<=m;x++){
					if ((i<=n0)&&(a[i]!=x))continue;
					for(int y=1;y<=m;y++){
						if ((i<n0)&&(a[i+1]!=y))continue;
						if (y<x){
							int g0=add(gp0[i-1][x-1][x+1],mod-gp0[i-1][y-1][x+1]);
							int g1=add(gp1[i-1][x-1][x+1],mod-gp1[i-1][y-1][x+1]);
							ans2=(ans2+(ll)(w<x ? g0 : g1)*(gs[i+2][y-1][x+1]+(y==w ? fs[i+2][y-1][x+1] : 0)))%mod;
						}
						if (y>x){
							int g0=add(gp0[i-1][x-1][x+1],mod-gp0[i-1][x-1][y+1]);
							int g1=add(gp1[i-1][x-1][x+1],mod-gp1[i-1][x-1][y+1]);
							ans2=(ans2+(ll)(w<x ? g0 : g1)*(gs[i+2][x-1][y+1]+(y==w ? fs[i+2][x-1][y+1] : 0)))%mod;
						}
					}
				}
		}
		printf("%d %d\n",ans1,ans2);
	}
	return 0;
}

标签:le,int,染色,元素,add,ge,数组,mod
From: https://www.cnblogs.com/PYWBKTDA/p/17288792.html

相关文章

  • 795. 区间子数组个数
    题目描述给一个数组,再给一个值的范围[l,r],问最大值在[l,r]之间的子数组有多少个?f1-双指针基本分析如果枚举子数组的右端点i,会有几种情况?(1)arr[i]>right;(left<=arr[i]<=right;(3)arr[i]<left假如枚举到右端点i,左端点怎么考虑?(1)的情况,这个子数组不满足,可以跳过;(2)......
  • 对于数组和指针的关系的测试
    #include"stdio.h"//验证数组和指针的以下一些关系//1.一元数组名本质上是数组第一个元素的地址,也是数组的地址//2。数组中存在a[2]=*(a+2)//3.数组在传递的时候传递的是数组名,也就是传递的是它的地址intmain(){intc[3]={1,2,3};int*a=c;//此时的a表示c数组......
  • 洛谷4113(树状数组+离线处理)
    [HEOI2012]采花题目描述萧薰儿是古国的公主,平时的一大爱好是采花。今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花。花园足够大,容纳了$n$朵花,共有$c$种颜色,用整数$1\simc$表示。且花是排成一排的,以便于公主采花。公主每次采花后会统计采到的花的颜色数,颜色......
  • vue数组和对象进行 watch 和 watchEffect 对比
    constarr1=ref([]);constarr2=reactive([]);constobj1=ref({});constobj2=reactive({});watchEffect(()=>{console.log("watchEffectarr1",arr1.value);console.log("watchEffectarr2",arr2)......
  • PHP 判断数组是否为空的方法
    1.isset功能:判断变量是否被初始化说明:它并不会判断变量是否为空,并且可以用来判断数组中元素是否被定义过注意:当使用isset来判断数组元素是否被初始化过时,它的效率比array_key_exists高4倍左右<?php$a='';$a['c']='';if(!isset($a))echo'$a未被初始化'."";if......
  • JavaScript:数组删除指定元素
    1.shift()方法用于删除数组中的第一个元素。注:此方法会改变数组的长度letarr=[1,2,3]arr.shift()//删除1//arr为[2,3]2.pop()方法用于删除数组中最后一个元素注:此方法会改变数组的长度letarr=[1,2,3]arr.pop();//删除3//arr为[1,2]3.splice()方法用于......
  • 力扣-数组-滑动窗口
    题目顺序209长度最小的子数组,904水果成篮解题思路1.滑动窗口求解的题目中,关键词为”求解连续“2.暴力解法是双重for循环,相当于对滑动窗口的起始和终止点都遍历3.滑动窗口求解是,只遍历终止点,当sum符合条件时,start++,向前一步缩小窗口4.终止条件是终止点end遍历完  1c......
  • js 递归遍历树形结构数据,返回新的数组
    工作中,我们经常会遇到这样的情况:后端返回的数组,只需要取name、value生成新的数组,或者是将某个属性名修改,生成新的数组。递归是一种常见的解决问题的方法,即把问题逐渐简单化。“递归”的基本思想是:自己调用自己。实例如下handleDg(arrs,that){arrs.map((item,index)......
  • 动态数组简介
                        动态数组定义:动态数组是指在声明时没有确定数组大小的数组,即忽略圆括号中的下标;当要用它时,可随时用ReDim语句重新指出数组的大小。使用动态数组的优点是可以根据用户需要,有效利用存储空间。特点数组到底应该有多大才......
  • 最长连续序列(并查集、数组)、复原 IP 地址(字符串、回溯)、删除链表的倒数第 N 个结
    最长连续序列(并查集、数组)给定一个未排序的整数数组nums,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。请你设计并实现时间复杂度为O(n)__的算法解决此问题。示例1:输入:nums=[100,4,200,1,3,2]输出:4解释:最长数字连续序列是[1,2,3,4]。它的长度为4......