noip模拟39
\(\color{white}{\mathbb{百般红紫博众爱,正是芳菲斗艳时,名之以:牡丹}}\)

%%% szs巨佬AK
\(t1\)、\(t4\) 都会做,剩下两道好像都不太会,再次扫描到知识盲区——竞赛图
特殊的 \(dp\) 题还是很难设计出一个标准的状态
(t1过水已隐藏)
B. 竞赛图
数据范围小一看是状压,然而并不知道竞赛图的性质,于是瞎推一阵后只打了个 \(tarjan\) 暴力,一测 \(19\) 的点跑了 \(2.3s\),以为能蹭过 \(60\) 的点(然而最后并没有)
竞赛图缩点后是链状,那么对于一个非强联通图,一定存在且仅存在一个子图 \(S\) 向补集的连边都是朝向补集方向的。那么对于每个集合 \(S\),对其所有 所有点的出边交集的子集标记为不合法即可
代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e7+5;
int n,all,op,ans,t,to[maxn];
bool flag[maxn];
int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
void init(){
for(int i=0;i<=all;i++)flag[i]=1,to[i]=0;
ans=0;
return ;
}
int main(){
t=read();
for(int i=1;i<=2e7;i++)flag[i]=1;
while(t--){
init();
n=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
op=read();
if(op)to[1<<(i-1)]|=(1<<(j-1));
}
}
all=(1<<n)-1;
to[0]=all;
for(int S=1;S<=all;S++){
int p=(S&-S);
to[S]=(to[p]&to[S^p]);
// cout<<S<<" "<<to[S]<<endl;
}
for(int S=1;S<=all;S++){
if(flag[S]){
for(int T=to[S];T;T=(T-1)&to[S]){
flag[T|S]=false;
}
}
}
for(int S=0;S<=all;S++)if(flag[S])ans++;
cout<<ans<<endl;
}
return 0;
}
C. 糖果
\(dp\) 神仙题
首先可以只关心 \(C\) 组选了哪些数,对于所选数的位置以及未选数的排列可以计算
考虑对于一个确定的数组排列,第一次一定是放第一个数,那么第一次前两个数的放置有 \((n-1)(n-2)\) 种,第二次摆放后有 \((n-4)(n-5)\) 种方法,那么最后答案只需要乘上 \(\prod (3i-1)(3i-2)\) 即可。
考虑 \(dp\) 统计,设 \(dp[i][j][k]\) 表示第一行扫到第 \(i\) 个位置,第二行扫到第 \(j\) 个位置,第三行有 \(k\) 个数在候选集合里的方案数。最后加一为维 \(0/1\) 表示当前更新是第几行,然后 \(dp\) 一列一列转移,先选第一行,再选第二行,用 \(0\) 转移到 \(1\),用 \(1\) 转移到下一个 \(0\)
考虑转移:
对于第一行的一个数可以选当且仅当第一行当前位置的数在第二行出现的位置晚于 \(j\),否则只能光移不选,于是有一下转移:
光移不选:
\]
选择当前,更新第二行:
\]
并更新第三行的备选集合(因为用了一个候选集合就少了一个):
\]
第二行类似,更新备选集合为:
\]
因为右移了一位,相当于候选集合里多了一个数
于是整个 \(dp\) 复杂度是 \(n^3\) 的
代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=405;
const int mod=1e9+7;
int n,a[maxn],posa[maxn],b[maxn],posb[maxn],f[maxn][maxn][maxn][2],ans;
int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
int main(){
n=read();
for(int i=1;i<=n;i++)a[i]=read(),posa[a[i]]=i;
for(int i=1;i<=n;i++)b[i]=read(),posb[b[i]]=i;
f[1][1][0][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=0;k<=n/3;k++){
if(f[i][j][k][0]){
if(posb[a[i]]<j){
f[i+1][j][k][0]=(f[i+1][j][k][0]+f[i][j][k][0])%mod;
}
else {
f[i][j][k][1]=(f[i][j][k][1]+f[i][j][k][0])%mod;
if(k)f[i+1][j][k-1][0]=(f[i+1][j][k-1][0]+1ll*f[i][j][k][0]*k%mod)%mod;
}
}
if(f[i][j][k][1]){
if(posa[b[j]]<i){
f[i][j+1][k][1]=(f[i][j+1][k][1]+f[i][j][k][1])%mod;
}
else if(b[j]!=a[i]){
if(k)f[i][j+1][k-1][1]=(f[i][j+1][k-1][1]+1ll*f[i][j][k][1]*k%mod)%mod;
f[i+1][j+1][k+1][0]=(f[i+1][j+1][k+1][0]+f[i][j][k][1])%mod;
}
}
}
}
}
for(int i=1;i<=n;i++)ans=(ans+f[n+1][i][0][0])%mod;
for(int i=1;i<=n/3;i++)ans=1ll*ans*(3*i-1)%mod*(3*i-2)%mod;
cout<<ans;
return 0;
}
D. 树
国赛 \(d1t1\) 原题,一条黑边相当于两端点更新时间不同,那么每次修改把路径上的节点时间戳都更新即可
代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=6e5+5;
const int maxm=1e6+5;
int n,q,x,y,hd[maxn],cnt,siz[maxn],fa[maxn],tp[maxn],son[maxn],op,ans,re[maxn],tot,id[maxn],dep[maxn];
int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
struct Edge{
int nxt,to;
}edge[maxm];
void add(int u,int v){
edge[++cnt].nxt=hd[u];
edge[cnt].to=v;
hd[u]=cnt;
return ;
}
void dfs(int u){
siz[u]=1;
for(int i=hd[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa[u])continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
return ;
}
void dfs1(int u,int top){
tp[u]=top;
id[u]=++tot;
re[tot]=u;
if(son[u])dfs1(son[u],top);
for(int i=hd[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa[u]||v==son[u])continue;
dfs1(v,v);
}
return ;
}
namespace p1{
int tim,dfn[maxn],d;
int lca(int x,int y){
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]])swap(x,y);
x=fa[tp[x]];
}
if(dep[x]>dep[y])swap(x,y);
return x;
}
void start(){
for(int i=1;i<=n;i++)dfn[i]=i;
tim=n;
for(int i=1;i<=q;i++){
op=read();
x=read();
y=read();
d=lca(x,y);
if(op==1){
tim++;
while(1){
// cout<<x<<" ";
dfn[x]=tim;
if(x==d)break;
x=fa[x];
}
while(y!=d){
dfn[y]=tim;
y=fa[y];
}
}
else{
ans=0;
while(x!=d){
ans+=(dfn[x]!=dfn[fa[x]]);
x=fa[x];
}
while(y!=d){
ans+=(dfn[y]!=dfn[fa[y]]);
y=fa[y];
}
printf("%d\n",ans);
}
}
return ;
}
}
namespace p2{
int dfn[maxn],tim;
struct Seg{
int l,r,lc,rc,num,lazy;
}t[maxn*4];
void merge(Seg &p,Seg x,Seg y){
if(!x.num){
p=y;
return ;
}
if(!y.num){
p=x;
return ;
}
p.num=x.num+y.num-(x.rc==y.lc);
p.lc=x.lc;
p.rc=y.rc;
return ;
}
void build(int p,int l,int r){
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].num=1;
t[p].lc=t[p].rc=dfn[re[l]];
return ;
}
int mid=t[p].l+t[p].r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
merge(t[p],t[p<<1],t[p<<1|1]);
return ;
}
void dospread(int p,int w){
t[p].num=1;
t[p].lc=t[p].rc=w;
t[p].lazy=w;
return ;
}
void spread(int p){
dospread(p<<1,t[p].lazy);
dospread(p<<1|1,t[p].lazy);
t[p].lazy=0;
return ;
}
void change(int p,int l,int r,int w){
if(t[p].l>=l&&t[p].r<=r){
dospread(p,w);
return ;
}
if(t[p].lazy)spread(p);
int mid=t[p].l+t[p].r>>1;
if(l<=mid)change(p<<1,l,r,w);
if(r>mid)change(p<<1|1,l,r,w);
merge(t[p],t[p<<1],t[p<<1|1]);
return ;
}
void modi(int x,int y){
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]])swap(x,y);
change(1,id[tp[x]],id[x],tim);
x=fa[tp[x]];
}
if(dep[x]<dep[y])swap(x,y);
change(1,id[y],id[x],tim);
// cout<<"ppp "<<x<<" "<<y<<" "<<id[y]<<" "<<id[x]<<" "<<t[1].num<<endl;
return ;
}
Seg ask(int p,int l,int r){
// cout<<l<<" "<<r<<" "<<t[p].l<<" "<<t[p].r<<endl;
if(t[p].l>=l&&t[p].r<=r)return t[p];
if(t[p].lazy)spread(p);
int mid=t[p].l+t[p].r>>1;
Seg ans;
ans.num=ans.lc=ans.rc=0;
if(l<=mid)ans=ask(p<<1,l,r);
if(r>mid)merge(ans,ans,ask(p<<1|1,l,r));
return ans;
}
int que(int x,int y){
Seg ansx,ansy;
ansx.num=ansx.lc=ansx.rc=ansy.num=ansy.lc=ansy.rc=0;
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]])swap(x,y),swap(ansx,ansy);
merge(ansx,ask(1,id[tp[x]],id[x]),ansx);
// cout<<x<<" "<<tp[tp[x]]<<" "<<id[x]<<" "<<id[x]<<" "<<ansx.num<<endl;
x=fa[tp[x]];
}
if(dep[x]<dep[y])swap(x,y),swap(ansx,ansy);
merge(ansx,ask(1,id[y],id[x]),ansx);
// cout<<x<<" "<<y<<" "<<id[y]<<" "<<id[x]<<" "<<ansx.num<<" "<<ansy.num<<endl;
// merge(ansx,ansx,ansy);
return ansx.num+ansy.num-(ansx.lc==ansy.lc)-1;//ansx.num-1;
}
void start(){
for(int i=1;i<=n;i++)dfn[i]=i;
tim=n;
build(1,1,n);
// cout<<t[1].num<<endl;
// cout<<"hhh"<<endl;
for(int i=1;i<=q;i++){
op=read();
x=read();
y=read();
if(op==1){唯有牡丹真国色,花开时节动京城。
tim++;
modi(x,y);
}
else{
printf("%d\n",que(x,y));
}
}
return ;
}
}
int main(){
// freopen("ex_tree3.in","r",stdin);
// freopen("my.out","w",stdout);
n=read();
for(int i=1;i<=n-1;i++){
x=read();
y=read();
add(x,y);
add(y,x);
}
dfs(1);
dfs1(1,1);
q=read();
// if(n<=1000)p1::start();
// else
p2::start();
return 0;
}
\(\color{white}{\mathbb{唯有牡丹真国色,开花时节动京城。}}\)
noip模拟39的更多相关文章
- Noip模拟39 2021.8.14
T1 打地鼠 都切掉了的简单题 1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 con ...
- 2021.8.14考试总结[NOIP模拟39]
T1 打地鼠 全场就俩人没切,还有一个是忘关$freopen$了. $code:$ 1 #include<bits/stdc++.h> 2 #define rin register sig ...
- NOIP模拟 39
考的嘛也不是. 伤心(怎么可能) T1稍想想组合数,然后牢记: 取模题随时取模,包括刚刚读入的数据 T2想到了基环树,然而不会打QAQ.. 非常简洁但非常大神的做法:随便断掉环上的一条边 利用“这条 ...
- NOIP模拟39:树
他们说这题与之前树剖的一道叫染色的题类似,好像真的是这样. 就是我们考虑这样一件事,就是每一次染白都可以看作是给链上的点打一个时间戳,那么可以发现,如果相邻的两个点的时间戳不同,那么他们之间的 ...
- [考试总结]noip模拟39
不写那么多没用的了 开题就发现 \(T4\) 原题, \(T1\) 大水题. 然后发现 \(T4\) 忘了.... 不扯了 打地鼠 大水题,我代码都不想放... 算了,还是放一下吧.. #includ ...
- NOIP模拟17.9.22
NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥
- NOIP 模拟4 T2
本题属于二和一问题 子问题相互对称 考虑对于问题一:知a求b 那么根据b数组定义式 显然能发现问题在于如何求dis(最短路) 有很多算法可供选择 dijsktra,floyed,bfs/dfs,spf ...
- noip模拟33
\(\color{white}{\mathbb{失足而坠千里,翻覆而没百足,名之以:深渊}}\) 这场考试的时间分配非常不科学 开题试图想 \(t1\) 正解,一个半小时后还是只有暴力,特别惊慌失措 ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
随机推荐
- 【NLP学习其四】如何构建自己用于训练的数据集?什么是词性标注?
数据集与词性标注 数据集是NLP中的重要一环. 但是提到数据集,很多人的第一个想法可能是:"这玩意从网上下载就好了,不用管". 真的不用管?最开始我也是这么认为的 于是我直奔CoN ...
- Windows服务器如何磁盘分区,Windows服务器磁盘分区常见的三种
原文来自:https://www.sohu.com/a/272133008_100217178 我怕链接会失效,故转载此篇文章,解析得很透彻,一目了然!记录. -------------------- ...
- k8s之Service详解-Service使用
实验环境准备 在使用service之前,首先利用deployment创建出3个pod,注意要为pod设置app=nginx-pod的标签 创建deployment.yaml,内容如下 apiVersi ...
- springboot整合javafx
原文(原码)参考地址: https://github.com/roskenet/springboot-javafx-support https://github.com/spartajet/javaf ...
- Android系统编程入门系列之服务Service齐头并进多线程任务
在上篇文章中初步了解了Android系统的四大组件之一的服务Service,在服务内可以执行无用户交互的耗时操作任务,但是包括之前关于界面系列文章在内,生命周期方法都是在主线程内被系统回调的.如果直接 ...
- 000 PCI Express协议入门指南目录
一.001 PCI Express体系结构(一)
- SpringBoot自定义参数验证器
前要 之前我们介绍了JSR-303验证方式,十分的方便Spring都帮我们封装好了,但是对一些复杂的验证,还是需要更加灵活的验证器的. JSR-303验证器传送门:https://www.jiansh ...
- dedecms织梦笔记
1.单标签用法{dede:标签名 属性="值".../}举例说明:{dede:include filename="head.htm" /}2.双标签用法:cha ...
- SpringCloud降级熔断 Hystrix
1.分布式核心知识之熔断.降级讲解 简介:系统负载过高,突发流量或者网络等各种异常情况介绍,常用的解决方案 1.熔断: 保险丝,熔断服务,为了防止整个系统故障,包含子和下游服务 下单服 ...
- JAVA中多态与C++多态的区别
原文出自:http://blog.csdn.net/hihui/article/details/8604779 #include <stdio.h> class Base { public ...