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 ...
 
随机推荐
- python分析《三国演义》,谁才是这部书的绝对主角(包含统计指定角色的方法)
			
前面分析统计了金庸名著<倚天屠龙记>中人物按照出现次数并排序 https://www.cnblogs.com/becks/p/11421214.html 然后使用pyecharts,统计B ...
 - Davinci 可视化系统部署安装及简单使用
			
Davinci 是一个目前比较热门的国内开源BI系统,功能比较完善,各种可视化效果也挺不错.主要获取数据的方式是通过编写SQL 创建数据视图来展示各种图表的. Davinci面向业务人员/数据工程师/ ...
 - 如何安装多个jdk并方便切换系统jdk版本
			
如何安装多个jdk并方便切换系统jdk版本 前言 在安装myeclipse时,压缩包中附带1.8.0的jdk,顺便安装并配置环境变量后发现系统默认的jdk变为了1.8.0.随后发现eclipse只支持 ...
 - [bug] IDEA springboot项目 访问静态资源 html页面 报404
			
原因 复制的静态资源目录没有编译 解决 检查target目录中,是否有static目录,若没有,重新右键项目install即可 若还不能解决,尝试浏览器缓存和IDEA编译设置,详见参考链接 参考 ht ...
 - [c++] 内存与变量
			
内存 程序代码区用来保存指令,常量区.全局数据区.堆.栈都用来保存数据 常量区和全局数据区有时也被合称为静态数据区,意思是这段内存专门用来保存数据,在程序运行期间一直存在 函数被调用时,会将参数.局部 ...
 - GCC链接时库顺序问题
			
GCC或G++在编译链接时,如果命令行中含有库,则要特别注意了.根据<C专家编程>5.3节中的提示,GCC在链接时对命令行时的处理顺序是从左到右.证据是GCC的MAN: -l librar ...
 - MegaCli是一款管理维护硬件RAID软件,可以通过它来了解当前raid卡的所有信息,包括 raid卡的型号,raid的阵列类型,raid 上各磁盘状态
			
MegaCli 监控raid状态 转载weixin_30344131 最后发布于2015-10-16 13:05:00 阅读数 简介 MegaCli是一款管理维护硬件RAID软件,可以通过它来了 ...
 - MyBatis 回顾 JDBC(一)
			
引言 学过 Java 的童鞋都知道,在 Java 中只有 JDBC 可以访问数据库,但是只要使用过 JDBC 的同学肯定也感受到 JDBC 访问数据库的繁琐, 需要编写大量的代码,经历一系列的步骤. ...
 - 10.21 nmap:网络探测工具和安全/端口扫描器
			
nmap命令 是一款开放源代码的网络探测和安全审核工具,是Network Mapper的缩写.其设计目标是快速地扫描大型网络.nmap可以发现网络上有哪些主机,主机提供了什么服务(应用程序名称和版本号 ...
 - linux小本
			
登陆CentOS 2.重启系统:reboot 3.设置客户机显示器分辨率 4.查看IP地址:ip addr 5.切换目录:cd 6.查看目录:ls 7.复制文件:cp 8.编辑文件:vi cd /et ...