题意:一个长度为$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. OpenCASCADE 平面与球面求交

    OpenCASCADE 平面与球面求交 eryar@163.com OpenCASCADE提供了类IntAna_QuadQuadGeo用来计算两个二次曲面quadric(球面.圆柱面.圆锥面及平面,平 ...

  2. Mybatis-SqlSessionFactoryBuilder,SessionFactory与SqlSession的并发控制

    SqlSessionFactoryBuilder 这个类可以被实例化,使用和丢弃.一旦你创建了 SqlSessionFactory 后,这个类就不需要存在了.因此 SqlSessionFactoryB ...

  3. Jqgrid 序号列宽度调整

    // 遍历jqgrid 使其序号列宽度为45 function setwidth() { $("table[role='grid']").each(function () {//j ...

  4. Mahout In Action-第一章:初识Mahout

    1. 初识Mahout 本章涵盖以下内容: Apache Mahout是什么? 现实中推荐系统引擎.聚类.分类概述 配置mahout 读者可能从本书的标题中猜测到,本书是一本讲解如何将mahout应用 ...

  5. Leetcode145. Binary Tree Postorder Traversal二叉树的后序遍历

    给定一个二叉树,返回它的 后序 遍历. 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 递归: class Solution { public: vector<int> res; ve ...

  6. JZOJ5822 【NOIP提高A组模拟2018.8.16】 量子纠缠

    这是一道很巧妙的题目. 今早,我调了好久,终于将它切掉了-- 题目 Description Input 第一行包含一个正整数 m,代表操作数. 接下来 m 行,每行可能有以下形式: 1 s 代表将数字 ...

  7. CODE[VS]1372:DNA

    Description 为了进一步分析外星生物,专家们决定对 DNA 进行切割.限制性核酸内切酶是基因工程中的重要的工具酶.它会识别一段碱基序列(说白了就是只包含 ATGC 的序列)并且切割开.Eco ...

  8. Django项目:CRM(客户关系管理系统)--69--59PerfectCRM实现king_admin行内编辑

    #base_admin.py # ————————24PerfectCRM实现King_admin自定义操作数据———————— from django.shortcuts import render ...

  9. ArcGIS 10.2 for Server 集群部署

    ArcGIS 10.2 for Server 具有很灵活的体系结构,而 ArcGIS 10.2  forServer site 可以包含一台或多台安装 GIS Server 的机器,这些参与ArcGI ...

  10. substring() 方法用于提取字符串中介于两个指定下标之间的字符。

    substring() 方法用于提取字符串中介于两个指定下标之间的字符. 语法 stringObject.substring(start,stop) 参数 描述 start 必需.一个非负的整数,规定 ...