题意:一个长度为$n$的序列,一些地方是$0$,一些地方是$1$,$-1$的地方你可以选择填$0$或者$1$,你可以选择连一些边$x->y$满足$x<y$

请问有多少种填数并连边的方法,使得交错路的个数的奇偶性是$p$

$n \leq 50$

5维dp,可以减一维

原本的5维分别是:现在考虑的是第几个位置,当前有多少个点是x(0/1),并且以它为结尾的交错路的个数的奇偶性是r(0/1)。

dp的值是方案数

我们发现,假如我们现在要更新的dp值是$dp[i][j][k][t]$,并且我枚举到的状态是当前这个点是1,以它为结尾有奇数个交错路。

那么1连向它的边不影响他的奇偶性,0连向它的边,是偶数个的也不影响它的奇偶性,

只有奇数的0才会影响它的奇偶性,那么如果以它为结尾有偶数数个交错路,那么它要和前面奇数个奇数的0连边

这个可以预处理组合数就可以了

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=50+7;
const ll mod=1e9+7;
ll n,Px,col[maxn],mi[maxn],ans;
ll dp[maxn][maxn][maxn][maxn],C[maxn][maxn],Cd[2][maxn];//black,0/1,white,0/1 char cc; ll ff;
template<typename T>void read(T& aa) {
aa=0;cc=getchar();ff=1;
while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
if(cc=='-') ff=-1,cc=getchar();
while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
aa*=ff;
} int main() {
read(n); read(Px);
For(i,1,n) read(col[i]);
C[0][0]=1;
For(i,1,n) {
C[i][0]=1;
For(j,1,i) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
For(i,0,n) {
For(j,0,i) Cd[j&1][i]+=C[i][j];
Cd[0][i]%=mod; Cd[1][i]%=mod;
}
mi[0]=1; For(i,1,n) mi[i]=mi[i-1]*2%mod;
dp[0][0][0][0]=1; ll r,x;
For(i,1,n) For(j,0,i) For(k,0,i-j) For(t,0,i-j-k) {
r=i-j-k-t;
if(col[i]!=1&&j+k>0) {//black,0/1
x=mi[j+k-1]*mi[t]%mod;
if(j) //black,0
dp[i][j][k][t]+=x*dp[i-1][j-1][k][t]%mod*Cd[1][r]%mod;
if(k) //black,1
dp[i][j][k][t]+=x*dp[i-1][j][k-1][t]%mod*Cd[0][r]%mod;
}
if(col[i]!=0&&t+r>0) {
x=mi[t+r-1]*mi[j]%mod;
if(t) //white,0
dp[i][j][k][t]+=x*dp[i-1][j][k][t-1]%mod*Cd[1][k]%mod;
if(r) //white,1
dp[i][j][k][t]+=x*dp[i-1][j][k][t]%mod*Cd[0][k]%mod;
}
dp[i][j][k][t]%=mod;
if(i==n&&((k+r)&1)==Px) ans+=dp[i][j][k][t];
}
printf("%lld\n",ans%mod);
return 0;
}

ud20180701:

今天才知道,这道题可以O(n)做……

考场上看到这道题,第一反应是惊喜,哇,做过,第二反应是,诶,数据范围2e5???

想了好久才想起当初怎么做的,印象很深自己当时是O(n^4)做的,还给Achen和NicoDafaGood讲过。

然后思考了一下,发现白偶和黑偶是可以合并的,于是优化成了O(n^3),得了65分

当时场上还发现了,如果当前是黑,前面含有白奇,那么转移到黑奇和黑偶的方案是相同的。

但是没有想到,这两个转移的方案和就是2^i,所以转移到一个就是2^(i-1)。(i是前面的点数,不包括自己)

然后就记录一下前面有没有白奇和黑奇,以及白奇的点数和黑奇的点数的奇偶性就可以了。

O(n^3)代码:

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
const int maxn=5000+7,maxt=507;
const ll mod=998244353;
ll n,d,a[maxn],mi[maxn],C[maxn][maxn];
ll f[2][maxt][maxt],g[maxn][2]; template<typename T>void read(T& aa) {
aa=0;char cc=getchar();T ff=1;
while((cc!='-')&&(cc<'0'||cc>'9')) cc=getchar();
if(cc=='-') ff=-1,cc=getchar();
while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
aa*=ff;
} ll solve() {//O(n^3)
mi[0]=1; For(i,1,n) mi[i]=mi[i-1]*2%mod;
C[0][0]=g[0][0]=1;
For(i,1,n) {
C[i][0]=g[i][0]=1;
For(j,1,i) {
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
g[i][j&1]+=C[i][j];
}
g[i][0]%=mod; g[i][1]%=mod;
}
int o=0,t; ll x,y; f[0][0][0]=1;
For(i,1,n) {
o^=1;
For(j,0,i) For(k,0,i-j) f[o][j][k]=0;
For(j,0,i-1) For(k,0,i-1-j) if(f[o^1][j][k]) {//j:white odd , k:black odd (1)
x=(f[o^1][j][k]%=mod); t=i-1-j-k;//t:even(black&white) (0)
if(a[i]!=1) {//white
y=x*mi[t+j]%mod;
f[o][j+1][k]+=y*g[k][0]%mod;//odd
f[o][j][k]+=y*g[k][1]%mod; //even
}
if(a[i]!=0) {//black
y=x*mi[t+k]%mod;
f[o][j][k+1]+=y*g[j][0]%mod;//odd
f[o][j][k]+=y*g[j][1]%mod; //even
}
}
}
ll rs=0;
For(i,0,n) For(j,0,n-i) if(f[o][i][j]) {
f[o][i][j]%=mod;
if(((i+j)&1)==d) rs+=f[o][i][j];
}
return rs%mod;
} int main() {
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
read(n); read(d);
For(i,1,n) read(a[i]);
printf("%lld\n",solve());
// cerr<<clock()<<"\n";
return 0;
}

O(n)代码:

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const ll mod=998244353;
const int maxn=1e6+7;
ll n,d,a[maxn],dp[maxn][3][3],mi[maxn]; template<typename T>void read(T& aa) {
aa=0;char cc=getchar();T ff=1;
while((cc!='-')&&(cc<'0'||cc>'9')) cc=getchar();
if(cc=='-') ff=-1,cc=getchar();
while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
aa*=ff;
} int main() {
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
read(n); read(d);
mi[0]=1; For(i,1,n) mi[i]=mi[i-1]*2%mod;
For(i,1,n) read(a[i]);
dp[0][0][0]=1;
For(i,0,n-1) For(j,0,2) For(k,0,2) if(dp[i][j][k]) {
dp[i][j][k]%=mod;
if(a[i+1]!=1) {//white
if(k) {
dp[i+1][j? 3-j:1][k]+=dp[i][j][k]*mi[i-1]%mod;
dp[i+1][j][k]+=dp[i][j][k]*mi[i-1]%mod;
}
else dp[i+1][j? 3-j:1][k]+=dp[i][j][k]*mi[i]%mod;
}
if(a[i+1]!=0) {//black
if(j) {
dp[i+1][j][k? 3-k:1]+=dp[i][j][k]*mi[i-1]%mod;
dp[i+1][j][k]+=dp[i][j][k]*mi[i-1]%mod;
}
else dp[i+1][j][k? 3-k:1]+=dp[i][j][k]*mi[i]%mod;
}
}
ll ans=0;
For(i,0,2) For(j,0,2) if(dp[n][i][j]&&((i+j)&1)==d) ans+=dp[n][i][j]%mod;
printf("%lld\n",ans%mod);
return 0;
}

  

cf round 482E Kuro and Topological Parity的更多相关文章

  1. Codeforces 979E Kuro and Topological Parity - 动态规划 - 组合数学

    题目传送门 传送点 题目大意 给定$n$个标号依次为$1, 2, \cdots, n$的点,其中一些点被染成一些颜色,剩下的点没有染色.你需要添加一些有向边并将剩下的点染色,满足有向边从编号小的一端指 ...

  2. Codeforces 979E Kuro and Topological Parity(dp)

    题面传送门 题意:有 \(n\) 个点,每个点要么被涂黑,要么被涂白,要么没有颜色. 现在你要: 给没有颜色的点图上颜色(黑色或白色) 在这 \(n\) 个点中连若干条有向边,可以不连通.但是只能从编 ...

  3. cf round 482D Kuro and GCD and XOR and SUM

    题意: 开始有个空集合,现在有两种操作: $(1,x)$:给集合加一个数$x$,$x \leq 10^5$; $(2,x,k,s)$:在集合中找一个$a$,满足$a \leq s-x$,而且$k|gc ...

  4. CF Round #551 (Div. 2) D

    CF Round #551 (Div. 2) D 链接 https://codeforces.com/contest/1153/problem/D 思路 不考虑赋值和贪心,考虑排名. 设\(dp_i\ ...

  5. CF Round #510 (Div. 2)

    前言:没想到那么快就打了第二场,题目难度比CF Round #509 (Div. 2)这场要难些,不过我依旧菜,这场更是被\(D\)题卡了,最后\(C\)题都来不及敲了..最后才\(A\)了\(3\) ...

  6. UOJ #30. [CF Round #278] Tourists

    UOJ #30. [CF Round #278] Tourists 题目大意 : 有一张 \(n\) 个点, \(m\) 条边的无向图,每一个点有一个点权 \(a_i\) ,你需要支持两种操作,第一种 ...

  7. 竞赛题解 - CF Round #524 Div.2

    CF Round #524 Div.2 - 竞赛题解 不容易CF有一场下午的比赛,开心的和一个神犇一起报了名 被虐爆--前两题水过去,第三题卡了好久,第四题毫无头绪QwQ Codeforces 传送门 ...

  8. 【前行&赛时总结】◇第4站&赛时9◇ CF Round 513 Div1+Div2

    ◇第4站&赛时9◇ CF Round 513 Div1+Div2 第一次在CF里涨Rating QWQ 深感不易……作blog以记之 ( ̄▽ ̄)" +Codeforces 的门为你打 ...

  9. CF Round #600 (Div 2) 解题报告(A~E)

    CF Round #600 (Div 2) 解题报告(A~E) A:Single Push 采用差分的思想,让\(b-a=c\),然后观察\(c\)序列是不是一个满足要求的序列 #include< ...

随机推荐

  1. iOS开发CoreData的多表关联

    1.多表关联 多表关联,对SQL 数据库的操作,在一张表的数据中可以引用另外一张表里的数据.通过 Entity 实体中的 Relationships 来实现,比起传统的 SQL 数据库来,更加简单. ...

  2. 微信开发SDK支持小程序 ,Jeewx-Api 1.3.1 版本发布

    JEEWX-API 是一款JAVA版的微信开发SDK,支持微信公众号.小程序.微信企业号.支付宝生活号SDK和微博SDK.你可以基于她 快速的傻瓜化的进行微信开发.支付窗开发和微博开发. 基于jeew ...

  3. ES6 学习笔记(基础)

    书链接:http://es6.ruanyifeng.com/ #.let let 不存在“变量提升” 暂时性死区(即:let 所定义的变量在局部作用域中不受外界影响) var tmp = 123; i ...

  4. Django之模板语言(二)-----Filter

    1.其他常用的模板语言: 通过模板语言可以让前端页面显示数据,数据可以是基本数据类型,也可以是对象亦或者对象的列表,结合着模板中的for.if等配合使用. 要注意前端页面中,出现没有后端数据的情况,随 ...

  5. drools跳转出现错误问题(400)

    400 Sorry, a technical error occurred. Please contact a system administrator. 今天drools的管理平台tomcat部署完 ...

  6. xsd解析xml

    下面讲述根据xml生成对应序列化反序列化类的过程,xml需要首先转化为xsd,然后再生成为实体类.其中,XSD是XML Schema Definition的缩写. 1.拥有一个xml文件 2.打开vs ...

  7. CodeForces - 1087D

    CodeForces - 1087Dhttps://vjudge.net/problem/2115151/origin2*和/叶子结点的个数 #include<iostream> #inc ...

  8. git的三个区域比较

    工作区: 暂存区: 提交区: 工作区与暂存区比较:git diff 工作区与提交区比较:git diff 提交hash码或者HEAD 暂存区与提交区比较:git diff --cached 两个不同提 ...

  9. html常用标签详解2-图片标签详解

    <img /> 1.图片标签的属性 图片标签属于行内块元素,它自身的属性有一下几个,听我娓娓道来: src:图片资源的路径(resourse),可以使绝对路径,也可以是相对路径 绝对路径: ...

  10. 深入浅出 Java Concurrency (21): 并发容器 part 6 可阻塞的BlockingQueue (1)[转]

    在<并发容器 part 4 并发队列与Queue简介>节中的类图中可以看到,对于Queue来说,BlockingQueue是主要的线程安全版本.这是一个可阻塞的版本,也就是允许添加/删除元 ...