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 ...
随机推荐
- Python实用案例,Python脚本,Python实现批量加水印
往期回顾 Python实现自动监测Github项目并打开网页 Python实现文件自动归类 Python实现帮你选择双色球号码 Python实现每日更换"必应图片"为"桌 ...
- kivy中文编程指南
Kivy中文编程指南,由网友翻译后,我整理目录及页面形式,便了浏览查阅. 点击下载
- js--class类、super和estends关键词的学习笔记
前言 JavaScript 语言在ES6中引入了 class 这一个关键字,在学习面试的中,经常会遇到面试官问到谈一下你对 ES6 中class的认识,同时我们的代码中如何去使用这个关键字,使用这个关 ...
- 关于document.write()方法重绘页面问题
学习的时候,document.write()被告知是用来将内容写进页面里面,同时也被告知document.write()方法会重绘页面,但是关于什么时候会重绘,什么时候不会重绘页面没有太多解释. 首先 ...
- Mol Cell | 张令强/贺福初/魏文毅/刘翠华揭示线性泛素化调控血管生成新机制
景杰学术 | 报道 泛素化修饰作为主要的蛋白质翻译后修饰之一,与细胞周期.应激反应.信号传导和DNA损伤修复等几乎所有的生命活动密切相关[1].泛素分子通常含有7个赖氨酸残基,通过这些残基可以和其他泛 ...
- Javac 编译器
编译过程 Javac 编译过程大致可以分为1个准备过程和3个处理过程: 准备过程:初始化插入式注解处理器. 解析与填充符号表过程,包括: 词法.语法分析,将源代码的字符流转变为标记集合,构造出抽象语法 ...
- Golang语言系列-14-单元测试
单元测试 字符串切割函数 package split_string import ( "fmt" "strings" ) // Split:切割字符串 // e ...
- Java中的形式参数和实际参数
一.概念 1.形式参数: 就是在定义函数或过程的时候命名的参数. 通俗讲就是一个记号. 2.实际参数: 就是在执行时,调用函数或过程时,传递给函数或过程的参数. 通俗讲就是实际值. 3.参数: 就是一 ...
- 001 七层OSI参考模型
一.什么是七层OSI参考模型 OSI(Open System Interconnect),即开放式系统互连.是国际标准化组织(ISO)制定的一个用于计算机或通信系统间互联的标准体系,一般称为OSI参考 ...
- S3C2440—10.代码重定位
文章目录 一.启动方式 1.1 NAND FLASH 启动 1.2 NOR FLASH 启动 二. 段的概念 2.1 重定位数据段 2.2 加载地址的引出 三.链接脚本 3.1 链接脚本的引入 3.2 ...