好神的题啊!

看了这题只会第一个subtask,又参考了HN-CJ鸽王zsy的题解,实在太菜了。

暴力转移是O(nc2),很显然没有分。考虑子任务1,2,只需要转移包含已染色格子的列,然后状态数只有O(nc),对于关键两列(即有染色的列)间,只有5种状态。而这个可以初始化转移,转移讨论有点复杂,而且我不会用数学公式,就不打出吧。转移后即可直接DP。然后对于子任务3,4,把它们分割即可,把两边方案乘起来就行了,于是可以做到O(nc),得到96分的好成绩。然后听Claris所述,DP所有转移操作即为T1的操作,于是可以做到O(n+c)

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+,mod=1e9+;
int n,m,tot,ans=,a[N],b[N],c[N],p[N],g[N][];
int qpow(int a,int b)
{
int ret=;
while(b)
{
if(b&)ret=1ll*ret*a%mod;
a=1ll*a*a%mod,b>>=;
}
return ret;
}
struct array{
int mul,add,inv,sum,top,s[N<<],f[N];
array(){mul=inv=;}
void modify(int x,int v)
{
sum=(sum+1ll*(mod-f[x])*mul+mod-add)%mod;
f[x]=1ll*(v-add+mod)*inv%mod,s[++top]=x,sum=(sum+v)%mod;
}
void plus(int v){sum=(sum+1ll*m*v)%mod,add=(add+v)%mod;}
void cover(int v)
{
while(top)f[s[top--]]=;
mul=inv=,add=v,sum=1ll*m*v%mod;
}
void mult(int v)
{
if(v)
sum=1ll*sum*v%mod,mul=1ll*mul*v%mod,add=1ll*add*v%mod,inv=1ll*inv*qpow(v,mod-)%mod;
else cover();
}
int query(int x)
{
if(x)return(1ll*f[x]*mul+add)%mod;
return sum;
}
}F;
void trans(int x,int y,int z,int w)
{
if(x!=y)
{
int fy=F.query(y),sum=(F.query()-fy+mod)%mod;
F.mult((g[z][^w]-g[z][]+mod)%mod);
F.plus((1ll*sum*g[z][]+1ll*fy*g[z][^w])%mod);
F.modify(x,(1ll*sum*g[z][^w]+1ll*fy*g[z][^w])%mod);
F.modify(y,);
}
else{
int sum=F.query();
F.mult((g[z][^w]-g[z][^w]+mod)%mod);
F.plus(1ll*sum*g[z][^w]%mod);
F.modify(x,);
}
}
void build(int x,int y,int z,int w)
{
if(w==x)F.cover(g[z][]),F.modify(x,),F.modify(y,g[z][]);
else if(w==y)F.cover(g[z][]),F.modify(x,g[z][]),F.modify(y,);
else F.cover(g[z][]),F.modify(x,g[z][]),F.modify(y,g[z][]),F.modify(w,);
}
void solve(int x,int y,int z,int w)
{
int ret=;
if(w==x)
{
int fy=F.query(y),sum=(F.query()-fy+mod)%mod;
ret=(1ll*sum*g[z][]+1ll*fy*g[z][])%mod;
}
else if(w==y)
{
int fx=F.query(x),sum=(F.query()-fx+mod)%mod;
ret=(1ll*sum*g[z][]+1ll*fx*g[z][])%mod;
}
else{
int fx=F.query(x),fy=F.query(y),sum=(1ll*F.query()-fx-fy+*mod)%mod;
ret=(1ll*sum*g[z][]+1ll*fx*g[z][]+1ll*fy*g[z][])%mod;
}
ans=1ll*ans*ret%mod;
}
int cal(int x,int y,int z,int u,int v)
{
if(x==u)return y==v?g[z][]:g[z][];
if(x==v)return y==u?g[z][]:g[z][];
if(y==u)return g[z][];
if(y==v)return g[z][];
return g[z][];
}
int main()
{
scanf("%d%d",&n,&m);
int mp[][]={{,,,m-,1ll*(m-)*(m-)%mod},
{,,m-,,1ll*(m-)*(m-)%mod},{,,m-,*m-,2ll*(m-)*(m-)%mod},
{,,*m-,m-,2ll*(m-)*(m-)%mod},{,,m-,m-,1ll*(m-)*(m-)%mod+}};
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]&&a[i]==a[i-]){puts("");return ;}
}
for(int i=;i<=n;i++)
{
scanf("%d",&b[i]);
if(b[i]&&(a[i]==b[i]||b[i]==b[i-])){puts("");return ;}
}
g[][]=;
for(int i=;i<=n;i++)
for(int j=;j<;j++)
for(int k=;k<;k++)
g[i][k]=(g[i][k]+1ll*g[i-][j]*mp[j][k])%mod;
int v1=qpow(m-,mod-),v2=qpow(1ll*(m-)*(m-)%mod,mod-);
for(int i=;i<=n;i++)
g[i][]=1ll*g[i][]*v1%mod,g[i][]=1ll*g[i][]*v1%mod,g[i][]=1ll*g[i][]*v2%mod;
for(int i=;i<=n;i++)
if(a[i]||b[i])
{
p[++tot]=i;
if(b[i]&&!a[i])swap(a[i],b[i]),c[i]=;
else if(b[i])c[i]=;
}
int pw=qpow(1ll*(m-)*(m-)%mod+,p[]-);
if(c[p[]]<)F.cover(pw),F.modify(a[p[]],);else ans=pw;
for(int i=;i<=tot;i++)
if(c[p[i-]]==)
if(c[p[i]]==)ans=1ll*ans*cal(a[p[i-]],b[p[i-]],p[i]-p[i-],a[p[i]],b[p[i]])%mod;
else{
if(c[p[i]])swap(a[p[i-]],b[p[i-]]);
build(a[p[i-]],b[p[i-]],p[i]-p[i-],a[p[i]]);
if(c[p[i]])swap(a[p[i-]],b[p[i-]]);
}
else if(c[p[i]]==)
{
if(c[p[i-]])swap(a[p[i]],b[p[i]]);
solve(a[p[i]],b[p[i]],p[i]-p[i-],a[p[i-]]);
if(c[p[i-]])swap(a[p[i]],b[p[i]]);
}
else trans(a[p[i-]],a[p[i]],p[i]-p[i-],c[p[i]]^c[p[i-]]);
if(c[p[tot]]<)ans=1ll*ans*F.query()%mod;
ans=1ll*ans*qpow(1ll*(m-)*(m-)%mod+,n-p[tot])%mod;
printf("%d",ans);
}

[SDOI2019]染色(DP)的更多相关文章

  1. Educational Codeforces Round 62 (Rated for Div. 2)E(染色DP,构造,思维,组合数学)

    #include<bits/stdc++.h>using namespace std;const long long mod=998244353;long long f[200007][2 ...

  2. 【POJ 1112】Team Them Up!(二分图染色+DP)

    Description Your task is to divide a number of persons into two teams, in such a way, that: everyone ...

  3. poj-1112 (二分图染色+dp分组)

    #include <iostream> #include <algorithm> #include <cstring> using namespace std; ; ...

  4. 【xsy1172】 染色 dp

    题目大意:现有$n$条排成一行的木板,每个木板有一个目标颜色.你每次能将一个区间内的木板分别染成它们的目标颜色,而这次染色的代价为这个区间内不同目标颜色的木板的数量的平方.问将全部木板染成目标颜色的最 ...

  5. BZOJ:2958 序列染色 DP

    bzoj2958 序列染色 题目传送门 Description 给出一个长度为N由B.W.X三种字符组成的字符串S,你需要把每一个X染成B或W中的一个. 对于给出的K,问有多少种染色方式使得存在整数a ...

  6. 染色dp(确定一行就可行)

    题:https://codeforces.com/contest/1027/problem/E 题意:给定n*n的方格,可以染黑白,要求相邻俩行”完全“不同或完全相同,对于列也是一样.然后限制不能拥有 ...

  7. 5.29 省选模拟赛 树的染色 dp 最优性优化

    LINK:树的染色 考场上以为这道题要爆蛋了 没想到 推出正解来了. 反正是先写了爆搜的 爆搜最近越写越熟练了 容易想到dp 容易设出状态 f[i][j]表示以i为根的子树内白色的值为j此时黑色的值怎 ...

  8. bzoj2958: 序列染色(DP)

    2958: 序列染色 题目:传送门 题解: 大难题啊(还是我太菜了) %一发大佬QTT 代码: #include<cstdio> #include<cstring> #incl ...

  9. Atcoder Grand Contest 031B(DP,思维)

    #include<bits/stdc++.h>using namespace std;int a[200007];int b[200007];long long dp[200007];lo ...

随机推荐

  1. 《Thinking in Java》位运算

    按位操作符: 首先先记住一件事,方便理解:是否对应正负对应10. 1.与(&):11得1,10得0,00得0. 2.或(|):11得1,10得1,00得0. 3.异或(^):11得0,10得1 ...

  2. 读写锁ReentrantReadWriteLock源代码浅析

    1.简介 并发中常用的ReentrantLock,是一种典型的排他锁,这类锁在同一时刻只允许一个线程进行访问,实际上将并行操作变成了串行操作.在并发量大的业务中,其整体效率.吞吐量不能满足实现的需要. ...

  3. POJ 1125:Stockbroker Grapevine

    Stockbroker Grapevine Time Limit: 1000MS   Memory Limit: 10000KB   64bit IO Format: %I64d & %I64 ...

  4. Chrome在新版MacOS上报错 NET::ERR_CERT_WEAK_KEY 解决方法

    现象 原文链接 证书详情: 原因 参考苹果官网给出的提示(https://support.apple.com/en-us/HT210176): RSA秘钥长度必须>=2048,小于这个长度的将不 ...

  5. if case for while

    #!/bin/basha=$1if [ $a ] #判断$1是否为空then #非空echo "the input is No:$a"exit 0else #空read -p &q ...

  6. Delphi生成即调用带窗体的Dll

    library frmDll; { Important note about DLL memory management: ShareMem must be the first unit in you ...

  7. java笔记5

    1. JUnit 单元测试:方法名任意,但是没有参数列表. 注解: @Test @Ignore @Before @After 2. 泛型 1. 在集合中使用泛型 2. 在通用性较高的代码中使用泛型 1 ...

  8. == 与 equals区别(HashCode方法)

    1:==分析 1.2:基本类型比较 判断基本类型的数值是不是相等 1.3:对象类型比较 判断两个引用是不是指向同一个对象,即内存地址是不是相等. 2:equals分析 来判断对象内容是不是相等,一般有 ...

  9. socket实践编程1

    1.服务器端程序编写 (1).socket (2).bind (3).listen (4).accept,返回值是一个fd,accept正确返回就表示我们已经和前来连接我的客户端之间建立了一个TCP连 ...

  10. Linux(CENTOS7) Jdk完整步骤安装

    方式一: 直接通过yum安装,这种方式比较方便,下面贴上安装jdk1.8*的命令: -openjdk* -y 上面命令执行完成之后,使用下面命令即可查看是否安装成功: java -version 方式 ...