NOIP模拟测试28「阴阳·虎·山洞」
写这几个题解我觉得我就像在按照官方题解抄一样
阴阳
题解
将题目中给的阴阳看作黑色和白色
首先我们观察到最后生成图中某种颜色必须是竖着单调递增或竖着单调递减

类似这样
否则不满足这个条件
但合法染色方案必须满足任意两个同颜色格子之间的格子也必须是该颜色。
然后我们分四种情况统计,
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「阴阳·虎·山洞」的更多相关文章
- NOIP模拟测试19「count·dinner·chess」
反思: 我考得最炸的一次 怎么说呢?简单的两个题0分,稍难(我还不敢说难,肯定又有人喷我)42分 前10分钟看T1,不会,觉得不可做,完全不可做,把它跳了 最后10分钟看T1,发现一个有点用的性质,仍 ...
- NOIP模拟测试30「return·one·magic」
magic 题解 首先原式指数肯定会爆$long$ $long$ 首先根据欧拉定理我们可以将原式换成$N^{\sum\limits_{i=1}^{i<=N} [gcd(i,N)==1] C_{G ...
- NOIP模拟测试38「金·斯诺·赤」
金 辗转相减见祖宗 高精 #include<bits/stdc++.h> using namespace std; #define A 2000 #define P 1 #define N ...
- NOIP模拟测试20「周·任·飞」
liu_runda出的题再次$\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%$ 任 题解 题目中为什么反复强调简单路径,没有环 没有环的图中点数-边数=联通块数 前缀和维护边 ...
- NOIP模拟测试23「mine·water·gcd」
mine 题解 一道比较水的dp 考试因为初始化挂掉了只有$80$分 代码有注释 #include<bits/stdc++.h> using namespace std; //无脑dp # ...
- NOIP模拟测试16「Drink·blue·weed」
话说这次考试 Drink 非常棒的一道卡常练习题,适合练习卡常 真的很棒 前置卡常知识 1.char要比int快 char是最快的 输出putchar,输入getchar 在这个题快了7000豪 2. ...
- NOIP模拟测试9「随·单·题」
liu_runda出的题,先$\%\%\%\%\%\%\%\%\%\%\%$为敬 随 考试时没有Qj 然后甚至没做,甚至没交 我不知道我怎么想的 这个题挺难改 你需要用到 循环矩阵快速幂,矩阵快速幂优 ...
- NOIP模拟测试4「礼物·通讯·奇袭」
礼物. 首先见到期望一定要想dp,看到n的范围无脑想状压, 然后我就只想到这了. dp方程式还是比较好想的,但是我依然想不出来 略经思考 颓题解 依然不会,随便写了个式子 i状态中不含j $f[i ...
- NOIP模拟测试21「折纸·不等式」
折纸 题解 考试时无限接近正解,然而最终也只是接近而已了 考虑模拟会爆炸,拿手折纸条试一试,很简单 考你动手能力 代码 #include<bits/stdc++.h> using name ...
随机推荐
- Spring Cloud Alibaba(9)---Sentinel概述
Sentinel概述 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentinel是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流.流量整形.熔断降级.系统自适应保护.热点防 ...
- Go - 开箱即用,WEB 界面一键安装,没有项目经验,可以拿这个练手
安装界面 启动程序之后,会在浏览器中自动打开安装界面. 因为程序会使用到 Redis 和 MySQL,所以安装前请输入 Redis.MySQL 配置信息,点击初始化按钮,会将用到的数据表和默认数据进行 ...
- https://www.jqhtml.com/30047.html strace + 命令: 这条命令十分强大,可以定位你程序到底是哪个地方出了问题
https://www.jqhtml.com/30047.html 我的Linux手册 服务器 浏览数:72 2019-1-30 原文链接 基础安装 # CentOS sudo yum install ...
- 攻防世界(三)Web_php_unserialize
攻防世界系列:Web_php_unserialize 0x01.代码审计 1.类Demo中struct().destruct()函数分别在代码执行开始和结束时调用.而wakeup函数会在代码执行过程中 ...
- MyBatis 高级查询环境准备(八)
MyBatis 高级查询 之前在学习 Mapper XML 映射文件时,说到 resultMap 标记是 MyBatis 中最重要最强大也是最复杂的标记,而且还提到后面会详细介绍它的高级用法. 听到高 ...
- Linux基础命令学习记录(一)
使用频繁的Linux命令 一.文件和目录 1.cd命令 cd / 进入根目录 cd .. 返回上一级目录 cd ../.. 返回上两级目录 cd 进入个人的主目录 cd ~ 进入个人的主目录 cd - ...
- (数据科学学习手札123)Python+Dash快速web应用开发——部署发布篇
1 简介 这是我的系列教程Python+Dash快速web应用开发的第二十期,在上一期中我介绍了利用内网穿透的方式,将任何可以联网的电脑作为"服务器"向外临时发布你的Dash应用. ...
- java命令的本质逻辑揭秘
前言 在日常编码中,有了ide的支持,我们已经很少直接在命令行中直接执行java XXX命令去启动一个项目了.然而我们有没有想过,一个简单的java命令背后究竟做了些什么事情?让我们看下下面几个简单的 ...
- 压力测试工具JMeter简单使用
场景:项目上线前自测服务器抗压能力or提供数据给品牌方展示 注意:测试单台机器不要使用很大的线程.每台机器的配置不同,"聚合报告"中的Error也不同. 如:20000线程请求,1 ...
- 微信小程序开发(后端Java)
微信使用的开发语言和文件很「特殊」. 小程序所使用的程序文件类型大致分为以下几种: ①WXML(WeiXin Mark Language,微信标记语言) ②WXSS(WeiXin Style Shee ...