写这几个题解我觉得我就像在按照官方题解抄一样

阴阳

题解

将题目中给的阴阳看作黑色和白色

首先我们观察到最后生成图中某种颜色必须是竖着单调递增或竖着单调递减

类似这样

否则不满足这个条件

但合法染色方案必须满足任意两个同颜色格子之间的格子也必须是该颜色。

然后我们分四种情况统计,

1.黑色居于左侧而且分界点单调不降,

2.黑色居于左侧而且分界点单调不升,

3.白色居于左侧而且分界点单调不降,

4.白色居于左侧而且分界点单调不升。

我们发现这样会算重,

dp然后手动容斥,

1,2会算重左面每列全是黑色

类似于

类似的3,4会算重左面全是白色

那么上面全是黑色我们也会算重(2,3)

上面全是白色我们仍然会算重

手动容斥

题解应该都能看懂,实现稍难(不用说了我码力太弱)

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 1111
const ll mod=1e9+7;
ll can[A][A][10],f[A][A][2],up[A][A],down[A][A];
//can定义为i行从1--j染成B剩下染成W是否合法
char ch[A][A];
ll n,m,flag1,flag2,ans;
int main(){
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++)
scanf("%s",ch[i]+1);
for(ll i=1;i<=n;i++){
ll maxpos=0;
for(ll j=1;j<=m;j++){
if(ch[i][j]=='W') break;
if(ch[i][j]=='B') maxpos=j;
}
for(ll j=maxpos+1;j<=m;j++)
if(ch[i][j]=='B'){
maxpos=m+1; break;
}
ll now=maxpos;
while(ch[i][now]!='W'&&now<=m)
can[i][now][1]=1,now++;
} for(ll i=1;i<=n;i++){
ll maxpos=m+1;
for(ll j=m;j>=1;j--){
if(ch[i][j]=='W') break;
if(ch[i][j]=='B') maxpos=j;
}
for(ll j=maxpos-1;j>=1;j--)
if(ch[i][j]=='B'){
maxpos=-1; break;
}
ll now=maxpos;
while(ch[i][now]!='W'&&now>=0)
can[i][m-now+1][2]=1,now--;
}
for(ll i=0;i<=m;i++)
up[0][i]=1,down[0][i]=1;
for(ll i=1;i<=n;i++){
for(ll j=0;j<=m;j++){
if(!can[i][j][1]) continue;
f[i][j][0]=up[i-1][j];
f[i][j][1]=down[i-1][j];
// printf("up[%lld][%lld]=%lld down=%lld\n",i-1,j,up[i-1][j],down[i-1][j]);
}
for(ll j=0;j<=m;j++)
up[i][j]=(up[i][j-1]+f[i][j][0])%mod/*,printf("f=%lld up=%lld\n",f[i][j][0],up[i][j])*/;
for(ll j=m;j>=0;j--)
down[i][j]=(down[i][j+1]+f[i][j][1])%mod;
// printf("up=%lld down=%lld\n",up[n][m],down[n][0]);
}
/* for(ll i=1;i<=n;i++,puts("")){
for(ll j=1;j<=m;j++){
printf("%lld ",can[i][j][1]);
}
}
*/ memset(f,0,sizeof(f));
ans=(ans+up[n][m]+down[n][0]+mod)%mod;
// printf("ans=%lld\n",ans);
for(ll i=1;i<=n;i++){
for(ll j=0;j<=m;j++){
if(!can[i][j][2]) continue;
f[i][j][0]=up[i-1][j];
f[i][j][1]=down[i-1][j];
}
for(ll j=0;j<=m;j++)
up[i][j]=(up[i][j-1]+f[i][j][0])%mod;
for(ll j=m;j>=0;j--)
down[i][j]=(down[i][j+1]+f[i][j][1])%mod;
}
// printf("up=%lld down=%lld\n",up[n][m],down[n][0]);
ans=(ans+up[n][m]+down[n][0]+mod)%mod;
// printf("ans=%lld\n",ans);
memset(f,0,sizeof(f));
//减去左右重复
for(ll i=1;i<m;i++){
ll flag=0;
for(ll j=1;j<=n;j++)
if(!can[j][i][1]){
flag=1;break;
}
if(!flag) ans--;
}
for(ll i=1;i<m;i++){
ll flag=0;
for(ll j=1;j<=n;j++)
if(!can[j][i][2]){
flag=1;break;
}
if(!flag) ans--;
}
//减去上下
//若上面为B下面只能为W
for(ll i=1;i<n;i++){
ll flag=0;
for(ll j=1;j<=i;j++)
if(!can[j][m][1]){
flag=1;break;
}
for(ll j=i+1;j<=n;j++)
if(!can[j][0][1]){
flag=1;break;
}
if(flag)continue;
ans--;
}
for(ll i=n;i>=2;i--){
ll flag=0;
for(ll j=1;j<=i-1;j++)
if(!can[j][0][1]){
flag=1;break;
}
for(ll j=i;j<=n;j++)
if(!can[j][m][1]){
flag=1;break;
}
if(flag)continue;
ans--;
}
for(ll i=1;i<=n;i++){
if(!can[i][0][1]) flag1=1;
if(!can[i][m][1]) flag2=1;
}
if(!flag1) ans-=3;
if(!flag2) ans-=3;
printf("%lld\n",(ans+mod)%mod);
}

题解

我们发现一条性质我们子树内两个点要变成黑色我们同时经过树外的边不会使次数变优(除了直接与lca相连的边)

然后根据这条性质,我们发现我们一定存在一种最优方案使任意两条染色路径互不相交

然后我们进行贪心

首先题目中给的无要求的边我们进行缩边

我们统计到当前子树都已经全部染成黑色了,那么我们只用考虑与它相连就行

拿下面这个图举例(假设全部为白边)

你考虑3时你6的子树都处理完了,然后你遇到两个白色边(3,6)(3,7)你贪心直接染色就行,那么如果最后剩下一个没有染色怎么办,显然我们不用管,我们发现与3相连的边(1,3)这条边是必定被染色的,2本来要和3进行染色让(1,2)(1,3)进行染色,我们现在把这个边拉过来变成(2,8)进行染色就行了

那么依据上文说的,我们只需要让与3相连白边个数(除了父亲与它相连边)/2就行了

推广到所有点统计白边个数/2即可

然后这样做对于根来说会出错,特判一下就AC了(对于根来说没有办法再让自己父亲拉边过来)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define R register
#define ll long long
inline ll read()//-------
{
ll aa=0;char cc=getchar();
while(cc<'0'||cc>'9') cc=getchar();
while(cc<='9'&&cc>='0')
{aa=(aa<<3)+(aa<<1)+(cc^48);cc=getchar();}
return aa;
}
const int N=1000005;
struct tree{
int v,last;
}tr[N<<1];
int tot,first[N];
inline void add(int x,int y)
{
tr[++tot]=(tree){y,first[x]};
first[x]=tot;return;
}
int n,ans,mp[N],vi[N];
int dfs(int x,int fa)
{
int sum=0;vi[x]=1;
for(R int i=first[x],v;i;i=tr[i].last){
v=tr[i].v;
if(v==fa)continue;
dfs(v,x);
sum^=1;
if(!sum)++ans;
}
return sum;
}
int main()
{
//freopen("tight.in","r",stdin);
//freopen("tight.out","w",stdout);
n=read();mp[1]=++mp[0];
for(R int i=2,x,y,z;i<=n;++i){
x=read();y=read();z=read();
if(!z){
if(mp[i])mp[x]=mp[i];
else if(mp[x])mp[i]=mp[x];
else mp[i]=mp[x]=++mp[0];
continue;
}
if(!mp[i])mp[i]=++mp[0];
if(!mp[x])mp[x]=++mp[0];
if(y)continue;
add(mp[i],mp[x]);
add(mp[x],mp[i]);
}
for(R int i=1;i<=mp[0];++i)
if(!vi[i])
if(dfs(i,i))++ans;
printf("%d",ans);
return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<vector>
#define R register
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return f*x;
}
const int maxn=1000005;
struct node{
int v,nxt,da;
}e[2*maxn];int h[maxn],nu;
void add(int x,int y,int fl)
{
e[++nu].v=y;
e[nu].da=fl;
e[nu].nxt=h[x];
h[x]=nu;
}
int n,f[maxn],ans;
int dfs(int x,int xf)
{
int cnt=0;
for(int i=h[x];i;i=e[i].nxt)
{
int y=e[i].v,k=e[i].da;
if(y==xf)continue;
int nw=dfs(y,x);
//cout<<x<<" "<<y<<" "<<k<<endl;
if(k==1){cnt++;continue;}
if(!nw)continue;
if(k==3)ans++;
else cnt++;
}
ans+=cnt/2;
if(cnt%2==0)return 0;
return 1;
}
int main()
{
//freopen("data","r",stdin);
n=read();
int qj1=1,num1=0;
for(int x=2;x<=n;++x)
{
int y=read(),s=read(),t=read(),fl;
if(t==0)fl=2;
if(s==0&&t==1)num1++,fl=1;
if(s==1&&t==1)fl=3;
add(x,y,fl);
add(y,x,fl);
}
int nw=dfs(1,0);
ans+=nw;
printf("%d\n",ans);
}/*
g++ 1.cpp -o 1
./1 */

NOIP模拟测试28「阴阳·虎·山洞」的更多相关文章

  1. NOIP模拟测试19「count·dinner·chess」

    反思: 我考得最炸的一次 怎么说呢?简单的两个题0分,稍难(我还不敢说难,肯定又有人喷我)42分 前10分钟看T1,不会,觉得不可做,完全不可做,把它跳了 最后10分钟看T1,发现一个有点用的性质,仍 ...

  2. NOIP模拟测试30「return·one·magic」

    magic 题解 首先原式指数肯定会爆$long$ $long$ 首先根据欧拉定理我们可以将原式换成$N^{\sum\limits_{i=1}^{i<=N} [gcd(i,N)==1] C_{G ...

  3. NOIP模拟测试38「金·斯诺·赤」

    金 辗转相减见祖宗 高精 #include<bits/stdc++.h> using namespace std; #define A 2000 #define P 1 #define N ...

  4. NOIP模拟测试20「周·任·飞」

    liu_runda出的题再次$\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%$ 任 题解 题目中为什么反复强调简单路径,没有环 没有环的图中点数-边数=联通块数 前缀和维护边 ...

  5. NOIP模拟测试23「mine·water·gcd」

    mine 题解 一道比较水的dp 考试因为初始化挂掉了只有$80$分 代码有注释 #include<bits/stdc++.h> using namespace std; //无脑dp # ...

  6. NOIP模拟测试16「Drink·blue·weed」

    话说这次考试 Drink 非常棒的一道卡常练习题,适合练习卡常 真的很棒 前置卡常知识 1.char要比int快 char是最快的 输出putchar,输入getchar 在这个题快了7000豪 2. ...

  7. NOIP模拟测试9「随·单·题」

    liu_runda出的题,先$\%\%\%\%\%\%\%\%\%\%\%$为敬 随 考试时没有Qj 然后甚至没做,甚至没交 我不知道我怎么想的 这个题挺难改 你需要用到 循环矩阵快速幂,矩阵快速幂优 ...

  8. NOIP模拟测试4「礼物·通讯·奇袭」

    礼物. 首先见到期望一定要想dp,看到n的范围无脑想状压, 然后我就只想到这了. dp方程式还是比较好想的,但是我依然想不出来 略经思考   颓题解 依然不会,随便写了个式子 i状态中不含j $f[i ...

  9. NOIP模拟测试21「折纸&#183;不等式」

    折纸 题解 考试时无限接近正解,然而最终也只是接近而已了 考虑模拟会爆炸,拿手折纸条试一试,很简单 考你动手能力 代码 #include<bits/stdc++.h> using name ...

随机推荐

  1. XAML一些控件的使用

    这节来讲一些XAML中常用控件的使用. Window Window控件是一个基础,它是其它控件的容器,我们可以通过修改其中的一些属性来设置窗体的显示效果,下面说一些最常用的属性: WindowStar ...

  2. C#读写内置类型的数据时是否原子操作

    Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uin ...

  3. mysql无列名注入

    0x00 原理   mysql无列名注入是报错注入的一个变种,前提是已知表名,但是不知道列名,或者只知道部分列名,可通过报错注入拼接查询自身表,当自表被拼接时,由于存在重复属性列,会将列信息报错返回, ...

  4. 用源码搭建LNMP环境+部署WordPress

    首先要做的是就是关闭Centos7.4的防火墙及selinux #systemctl stop firewalld #systemctl disable firewalld #sed -ri 's/^ ...

  5. kvm虚拟机迁移(6)

    一.迁移简介 迁移:      系统的迁移是指把源主机上的操作系统和应用程序移动到目的主机,并且能够在目的主机上正常运行. 在没有虚拟机的时代,物理机之间的迁移依靠的是系统备份和恢复技术.在源主机上实 ...

  6. git OpenSSL SSL_connect问题

    遇到这个问题,查找别人也遇到,省时间不写了直接复制 在使用Git来克隆仓库报了错误,如下: fatal: unable to access 'https://github.com/xingbuxing ...

  7. C语言变量和函数命名规范

    C 语言变量和函数命名规范: 关于C语言变量和函数命名规范 据考察,没有一种命名规则可以让所有的程序员赞同,程序设计教科书一般都不指定命名规则.命名规则对软件产品而言并不是"成败悠关&quo ...

  8. Lua的string库函数列表

    基本函数 函数 描述 示例 结果 len 计算字符串长度 string.len("abcd") 4 rep 返回字符串s的n个拷贝 string.rep("abcd&qu ...

  9. 如何在idea中将项目生成API文档(超详细)(Day_32)

    1.打开要生成API文档的项目,点击菜单栏中的Tools工具,选择Generate JavaDoc 2.打开如下所示的Specify Generate JavaDoc Scope 界面 3.解释下Ot ...

  10. 『动善时』JMeter基础 — 25、JMeter参数化补充练习

    目录 1.使用"CSV数据文件设置"组件实现参数化 (1)测试计划中的元件 (2)数据文件内容 (3)线程组元件内容 (4)HTTP信息头管理器组件内容 (5)CSV数据文件设置组 ...