P5241 序列
分析
题目要求在一共加入若干条边是的不同B序列的个数;方便统计,我们不妨让一个B序列对应一种特定的操作来构造,具体如下
从1开始按从小到大加入点,始终维护一个顺序为加点次序的链;每次加入一条有向边
不会影响SCC个数的
1)连上新点:链末尾与新点连
2)连上废边:加上一条不改变强连通情况的边,不改变链
(两个决策每次必须只选一种,钦定为能加点加点,否则考虑连废边)
会影响的SCC个数
3)把链上与1强连通的部分(钦定为链的前缀)向后扩展若干
应注意到任意时刻SCC的数目为n-(j+1),n是图的点集大小,j是当前与1强连通的点集大小。
这样的构造与B序列是一一对应的,于是我们可以考虑计数dp,设f[i,j,k]为已经加入了i条边,与1强连通的链前缀长度为j+1,除此之外还有长度k的不同的B序列的个数。
转移和一些约束如下
f[0,0,0]=1
f[i,j,k]->f[i+1,j,k+1] j+1+k<n
f[i,j,k]->f[i+1,j,k] j+1+k==n且j*(j+1)+k(k-1)/2+(j+1)*k>i (注意是有向边哦)
f[i,j,k]->f[i+1,j+t,k-t] 0<t<=k 需要前缀和优化
实现
先留坑好了。 以下是暴力代码(80)
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
inline void add(int&x,int y) {
if((x+=y)>=mod) x-=mod;
}
int n,now,nxt=1;
int f[2][401][401],t[401][401];
int main() {
scanf("%d",&n);
f[now][0][0]=1;
for(int i=0; i<n*(n-1); ++i,now=nxt,nxt^=1) {
for(int j=0; j<n; ++j) {
for(int k=0; j+k<n; ++k) {
if(!f[now][j][k]) continue;
if(j+1+k<n) add(f[nxt][j][k+1],f[now][j][k]);
else if(j*(j+1)+k*(k-1)/2+(j+1)*k>i) add(f[nxt][j][k],f[now][j][k]);
if(k>0) add(t[j+1][k-1],f[now][j][k]);
f[now][j][k]=0;
}
}
for(int j=0; j<n; ++j) {
for(int k=0; j+k<n; ++k) {
add(f[nxt][j][k],t[j][k]);
if(k>0) add(t[j+1][k-1],t[j][k]);
t[j][k]=0;
}
}
int ans=0;
for(int j=0; j<n; ++j) {
for(int k=0; j+k<n; ++k) {
add(ans,f[nxt][j][k]);
}
}
printf("%d ",ans);
}
return 0;
}
优化状态数目并吸氧的代码
// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
const int N=400+5;
const int mod=1e9+7;
int n;
int now,nxt=1,f[2][N][N],t[N][N];
#define push(c,x,y) sta[c][++top[c]]=make_pair(x,y)
int mx,top[2],tmp[N];
pair<int,int> sta[2][20*N*N];
bool vis[N];
inline void add(int&x,int y) {
if((x+=y)>=mod) x-=mod;
}
int main() {
scanf("%d",&n);
f[now][0][0]=1;
push(now,0,0);
for(int i=0; i<n*(n-1); ++i,now=nxt,nxt^=1) {
top[nxt]=0;
for(int p=1; p<=top[now]; ++p) {
int j=sta[now][p].first;
int k=sta[now][p].second;
// printf("|%d,%d>,",j,k);
if(!f[now][j][k]) continue;
if(j+1+k<n) {
add(f[nxt][j][k+1],f[now][j][k]);
push(nxt,j,k+1);
} else if(j*(j+1)+k*(k-1)/2+(j+1)*k>i) {
add(f[nxt][j][k],f[now][j][k]);
push(nxt,j,k);
}
if(k>0) {
add(t[j+1][k-1],f[now][j][k]);
vis[j+k]=true;
}
f[now][j][k]=0;
}
int c=0,pre=top[nxt];
for(int s=0; s<n; ++s) if(vis[s]) {
vis[s]=false; tmp[++c]=s;
}
for(int j=0; j<n; ++j) {
for(int p=c; p; --p) {
int k=tmp[p];
if(k<0) break;
add(f[nxt][j][k],t[j][k]);
if(f[nxt][j][k]) push(nxt,j,k);
if(k>0) add(t[j+1][k-1],t[j][k]);
t[j][k]=0; tmp[p]--;
}
}
merge(sta[nxt]+1,sta[nxt]+pre+1,sta[nxt]+pre+1,sta[nxt]+top[nxt]+1,sta[nxt]+1); //归并
top[nxt]=unique(sta[nxt]+1,sta[nxt]+top[nxt]+1)-sta[nxt]-1;
int ans=0;
for(int p=1; p<=top[nxt]; ++p) {
add(ans,f[nxt][sta[nxt][p].first][sta[nxt][p].second]);
}
printf("%d ",ans);
}
return 0;
}
P5241 序列的更多相关文章
- P5241 序列(滚动数组+前缀和优化dp)
P5241 序列 挺神仙的一题 看看除了dp好像没什么其他办法了 想着怎么构个具体的图出来,然鹅不太现实. 于是我们想办法用几个参数来表示dp数组 加了几条边肯定要的吧,于是加个参数$i$表示已加了$ ...
- 【夯实PHP基础】UML序列图总结
原文地址 序列图主要用于展示对象之间交互的顺序. 序列图将交互关系表示为一个二维图.纵向是时间轴,时间沿竖线向下延伸.横向轴代表了在协作中各独立对象的类元角色.类元角色用生命线表示.当对象存在时,角色 ...
- Windows10-UWP中设备序列显示不同XAML的三种方式[3]
阅读目录: 概述 DeviceFamily-Type文件夹 DeviceFamily-Type扩展 InitializeComponent重载 结论 概述 Windows10-UWP(Universa ...
- 软件工程里的UML序列图的概念和总结
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习! 软件工程的一般开发过程:愿景分析.业务建模,需求分析,健壮性设计,关键设计,最终设计,实现…… 时序图也叫序列图(交互图),属于软件 ...
- python序列,字典备忘
初识python备忘: 序列:列表,字符串,元组len(d),d[id],del d[id],data in d函数:cmp(x,y),len(seq),list(seq)根据字符串创建列表,max( ...
- BZOJ 1251: 序列终结者 [splay]
1251: 序列终结者 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 3778 Solved: 1583[Submit][Status][Discu ...
- 最长不下降序列nlogn算法
显然n方算法在比赛中是没有什么用的(不会这么容易就过的),所以nlogn的算法尤为重要. 分析: 开2个数组,一个a记原数,f[k]表示长度为f的不下降子序列末尾元素的最小值,tot表示当前已知的最长 ...
- [LeetCode] Sequence Reconstruction 序列重建
Check whether the original sequence org can be uniquely reconstructed from the sequences in seqs. Th ...
- [LeetCode] Binary Tree Longest Consecutive Sequence 二叉树最长连续序列
Given a binary tree, find the length of the longest consecutive sequence path. The path refers to an ...
随机推荐
- 「JOISC 2018 Day 3」比太郎的聚会
题解: 很套路的题目 我们按照询问中的不算的个数是否大于$block$分类 如果大于,就$O(n)dp$一下 如果小于,就预处理出到每个点前$block$小的点 $block取\sqrt{n}$的话复 ...
- c/c++再学习:排序算法了解
1.冒泡排序 冒泡排序是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成. ...
- 【MSVC】_invalid_parameter和_invoke_watson
最近遇到一个崩溃问题,崩溃在CRT中,最后调用的函数是_invoke_watson.调用关系大概如下: _invoke_watson _invalid_parameter _invalid_param ...
- windows jdk安装
先去官网下载安装包 x86 32位 x64 64位 下载地址 安装jdk 安装目录默认c盘 配置系统环境 JAVA_HOME环境变量.作用:它指向jdk的安装目录,Eclipse/NetBeans/T ...
- SQL 获取表结构
select [表名]=c.Name, [表说明]=isnull(f.[value],''), [列序号]=a.Column_id, [列名]=a.Name, [列说明]=isnull(e.[valu ...
- Python+Tkinter 实现计算器功能
#=================================================================================== import tkinter ...
- 支持不同Android设备,包括:不同尺寸屏幕、不同屏幕密度、不同系统设置
Some of the important variations that you should consider include different languages, screen sizes, ...
- UWB DWM1000 跟随小车原理---一张图演示
更多内容参考论坛:bphero.com.cn
- JTAG各类接口针脚定义及含义
注:转自 揽月阁 JTAG有10pin的.14pin的和20pin的,尽管引脚数和引脚的排列顺序不同,但是其中有一些引脚是一样的,各个引脚的定义如下. 一.引脚定义 Test Clock Input ...
- xampp访问phpmyadmin访问不了
我的xampp版本是xampp-linux-x64-5.6.15-2-installer.run, 浏览器输入“我的ip/phpmyadmin”出现如下问题: Access forbidden! Ne ...