你那无聊的幻想,就由我来打破!

前言

补坑中。。

我都不知道自己这场模拟赛怎么打的了。

非常玄学,前三个小时一直在想正解,然后最后 20min 感觉 T1 不太稳,就又加上了一个暴力。

后来一看只有最后码的那个 8min 码完的暴力有分,其它的就。。

T1 matrix

解题思路

考场上一眼看出是状压,然后猛想一个小时 \(n\times 2^n\) 的打法,最后骗过了样例就溜了。

正解就是状压,只不过我好像少压了一维。。

先看 70pts 的做法,枚举第 i,i-1,i+1 层的按钮状态进行转移。

\(f_{i,j,k}\) 第 i 行按钮状态为 j 上一行的按钮状态为 k。

对于同一行里的情况直接把本行的开关状态或上左移一位右移一位就好了。

实现不是很难,注意边界情况就好了,时间复杂度:\(\mathcal{O}(n\times 2^{3m})\)

考虑优化状压:对于表示的状态进行更改。

\(f_{i,j,k}\) 第 i 行覆盖状态为 j 按钮状态为 k 。

然后循环的时候枚举每一行的覆盖状态以及这一行的按钮状态还有下一行的按钮状态。

这样时候对于 i-1 行的状态就可以剪掉一些。

(证明来自 pyt )本来有 00,01,10,11四种状态,现在枚举到的实际上只有后三种,因此时间复杂度为

\(\mathcal{O}(n\times 2^{m}\times 3^{m})\)

同样是要注意边界问题。

code

70pts

#include<bits/stdc++.h>
#define int long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,m,INF,ans,s[15][15],val[15][15],st[15];
int f[15][1<<11][1<<11],v[15][1<<11];
string ch;
signed main()
{
n=read();
m=read();
for(int i=1;i<=n;i++)
{
cin>>ch;
for(int j=1;j<=m;j++)
s[i][j]=ch[j-1]-'0';
}
for(int i=1;i<=n;i++)
s[i][m+1]=s[i][0]=1;
for(int i=1;i<=m;i++)
s[0][i]=s[n+1][i]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
val[i][j]=read();
for(int i=1;i<=n;i++)
for(int sta=0;sta<(1<<m);sta++)
for(int j=1;j<=m;j++)
if((sta>>j-1)&1)
v[i][sta]+=val[i][j];
for(int i=1;i<=n;i++)
{
for(int j=m;j>=1;j--)
st[i]=(st[i]<<1)|s[i][j];
}
st[0]=(1<<m)-1;
memset(f,0x3f,sizeof(f));
INF=f[0][0][0];
ans=INF;
f[1][0][0]=f[0][0][0]=0;
for(int i=0;i<=n;i++)
for(int s1=0;s1<(1<<m);s1++)
for(int s2=0;s2<(1<<m);s2++)
for(int s3=0;s3<(1<<m);s3++)
{
int sta=0;
sta|=st[i]|s1|s3|s2|(s2<<1)|(s2>>1);
sta&=(1<<m)-1;
if(sta==(1<<m)-1&&f[i][s2][s1]<INF)
f[i+1][s3][s2]=min(f[i+1][s3][s2],f[i][s2][s1]+v[i+1][s3]);
}
for(int i=0;i<(1<<m);i++)
ans=min(ans,f[n+1][0][i]);
printf("%lld",ans);
return 0;
}

正解

#include<bits/stdc++.h>
#define int long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,m,INF,ans,s[15][15],val[15][15],st[15];
int f[15][1<<11][1<<11],v[15][1<<11];
string ch;
signed main()
{
n=read();
m=read();
for(int i=1;i<=n;i++)
{
cin>>ch;
for(int j=1;j<=m;j++)
s[i][j]=ch[j-1]-'0';
}
for(int i=1;i<=n;i++)
s[i][m+1]=s[i][0]=1;
for(int i=1;i<=m;i++)
s[0][i]=s[n+1][i]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
val[i][j]=read();
for(int i=1;i<=n;i++)
for(int sta=0;sta<(1<<m);sta++)
for(int j=1;j<=m;j++)
if((sta>>j-1)&1)
v[i][sta]+=val[i][j];
for(int i=1;i<=n;i++)
for(int j=m;j>=1;j--)
st[i]=(st[i]<<1)|s[i][j];
st[0]=(1<<m)-1;
memset(f,0x3f,sizeof(f));
INF=f[0][0][0];
ans=INF;
f[1][st[1]][0]=f[0][st[0]][0]=0;
for(int i=0;i<=n;i++)
{
for(int s2=0;s2<(1<<m);s2++)
{
for(int s3=0;s3<(1<<m);s3++)
{
if((s2|s3)==(1<<m)-1)
for(int s1=0;s1<(1<<m);s1++)
{
if(f[i][s2][s1]<INF)
{
int jt=((s3<<1)|(s3>>1)|s3|s1|st[i+1])&((1<<m)-1);
f[i+1][jt][s3]=min(f[i+1][jt][s3],f[i][s2][s1]+v[i+1][s3]);
}
}
}
}
}
for(int i=0;i<(1<<m);i++)
ans=min(ans,f[n][(1<<m)-1][i]);
printf("%lld",ans);
return 0;
}

T2 block

解题思路

第一问比较简单。

对于方案数,考虑将点按照 value 从大到小排序之后依次加入序列。

则对于第 i 个点放的位置需满足 \(pos-1<key_i\) ,将依次乘以位置个数即可。

注意对于 value 相等情况要特殊处理,即当 value 相等时,按照 \(key_i\)从小到大排序。

保证上一个放的位置下一个一定能放就好了。

原因显然,因为是从大到小加入的,所以最大可已放在 i 前面的数的数量一定是 key 的值和他位置的较小值。

把第二问单独拿出来搞,与第一问没有任何联系。。

一定要线段树优化,对于符合条件的数一定是选字典序较小的,这里可以在线段树里处理出来。

当我们新加入一个数的时候比它小的数之前可以放的数就会减1,直接区间修改。

同样的如果有前面只可以再放一个比他大数,那么放入的数一定是小于等于它的。

否则直接在全部区间选择字典序最小的。

边界以及细节问题非常多,尤其是某处的等号。。。

code

#include<bits/stdc++.h>
#define int long long
#define end xxxxxxxxx
#define f() cout<<"Pass"<<endl
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=5e5+10,mod=1e9+7,INF=1e18;
struct Node
{
int val,key;
bool friend operator < (Node x,Node y)
{
if(x.val==y.val) return x.key<y.key;
return x.val>y.val;
}
}s[N];
struct Segment_Tree
{
int id,kid,key,laz;
}tre[N<<2];
int n,sum,ans=1,top,sta[N],pre[N],end[N];
bool comp(Node x,Node y)
{
if(x.val==y.val) return x.key<y.key;
return x.val<y.val;
}
int nmin(int x,int y)
{
if(s[x].key==s[y].key) return (s[x].val<s[y].val)?x:y;
return (s[x].key<s[y].key)?x:y;
}
void push_up(int x)
{
tre[x].key=min(tre[ls].key,tre[rs].key);
tre[x].id=nmin(tre[ls].id,tre[rs].id);
tre[x].kid=(tre[ls].key<=tre[rs].key)?tre[ls].kid:tre[rs].kid;
}
void push_down(int x)
{
if(!tre[x].laz) return ;
tre[ls].laz+=tre[x].laz;
tre[rs].laz+=tre[x].laz;
tre[ls].key-=tre[x].laz;
tre[rs].key-=tre[x].laz;
tre[x].laz=0;
}
void build(int x,int l,int r)
{
if(l==r)
{
tre[x].key=s[l].key;
tre[x].id=l;
tre[x].kid=l;
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
push_up(x);
}
int query(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tre[x].id;
push_down(x);
int mid=(l+r)>>1,id=0;
if(L<=mid) id=query(ls,l,mid,L,R);
if(R>mid) id=nmin(id,query(rs,mid+1,r,L,R));
push_up(x);
return id;
}
void update(int x,int l,int r,int L,int R)
{
if(L>R) return ;
if(L<=l&&r<=R)
{
tre[x].laz+=1;
tre[x].key-=1;
return ;
}
push_down(x);
int mid=(l+r)>>1;
if(L<=mid) update(ls,l,mid,L,R);
if(R>mid) update(rs,mid+1,r,L,R);
push_up(x);
}
void modify(int x,int l,int r,int pos)
{
if(l==r)
{
tre[x].kid=INF;
tre[x].key=INF;
tre[x].id=0;
return ;
}
push_down(x);
int mid=(l+r)>>1;
if(pos<=mid) modify(ls,l,mid,pos);
else modify(rs,mid+1,r,pos);
push_up(x);
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
s[i].key=read();
s[i].val=read();
}
sort(s+1,s+n+1);
for(int i=1;i<=n;i++)
if(s[i].val==s[i-1].val)
{
ans=ans*min(i,s[i].key+sum)%mod;
sum++;
}
else
{
ans=ans*min(i,s[i].key)%mod;
sum=1;
}
printf("%lld\n",ans);
sort(s+1,s+n+1,comp);
s[0].key=s[0].val=INF;
end[n]=n;
for(int i=2;i<=n;i++)
if(s[i].val==s[i-1].val) pre[i]=pre[i-1];
else pre[i]=i-1;
for(int i=n-1;i>=1;i--)
if(s[i].val==s[i+1].val) end[i]=end[i+1];
else end[i]=i;
build(1,1,n);
for(int i=1,id;i<=n;i++)
{
if(tre[1].key==1) id=query(1,1,n,1,end[tre[1].kid]);
else id=tre[1].id;
sta[++top]=id;
update(1,1,n,1,pre[id]);
modify(1,1,n,id);
}
for(int i=1;i<=top;i++) printf("%lld %lld\n",s[sta[i]].key,s[sta[i]].val);
return 0;
}

T3 graph

解题思路

尤其的恶心。。

思路就是分层图(其实就是二维 Dij 或者DPFA)+凸包维护。

首先对于不同的路径中经过的 -1 边的数量,进行分层图处理。

发现对于所有的 i 其实需要的只有 \(dis_{i,n}\)

并且对于所有的边(假设 -1 边为 x)都可以表示为 \(kx+b\)

所有相同的 k 我们只需要 b 值最小的,这里可以用凸包维护。

然后在跑一遍 Dij 就可以得出答案了。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=1e3+10,M=2e3+10,Mx=1e3;
int tot,head[N],nxt[M<<1],ver[M<<1],edge[M<<1];
int n,m,top,sta[N],dis[N][N],ans[N];
bool vis[N][N];
priority_queue<pair<int,int> > q[N];
queue<pair<int,int> > que;
vector<int> pre[N][N];
void add_edge(int x,int y,int val)
{
ver[++tot]=y;
edge[tot]=val;
nxt[tot]=head[x];
head[x]=tot;
}
signed main()
{
n=read();
m=read();
for(int i=1,x,y,val;i<=m;i++)
{
x=read();
y=read();
val=read();
add_edge(x,y,val);
add_edge(y,x,val);
}
q[0].push(make_pair(0,1));
memset(dis,0x3f,sizeof(dis));
dis[0][1]=0;
for(int k=0;k<=n;k++)
while(!q[k].empty())
{
int dist=-q[k].top().first,x=q[k].top().second;
q[k].pop();
for(int i=head[x],tmp,base,val;i;i=nxt[i])
{
int to=ver[i];
if(edge[i]==-1) tmp=1,base=1e3,val=0;
else tmp=0,base=0,val=edge[i];
if(dis[k+tmp][to]>=dist+val)
{
if(dis[k+tmp][to]>dist+val)
{
vector<int>().swap(pre[k+tmp][to]);
dis[k+tmp][to]=dist+val;
q[k+tmp].push(make_pair(-dis[k+tmp][to],to));
}
pre[k+tmp][to].push_back(x+base);
}
}
}
for(int i=0;i<=n;i++)
{
if(top&&dis[i][n]>dis[sta[top]][n]) continue;
while(top>1)
{
int tmp1=ceil((1.0*dis[sta[top]][n]-1.0*dis[i][n])/(1.0*i-1.0*sta[top]));
int tmp2=(dis[sta[top-1]][n]-dis[i][n])/(i-sta[top-1]);
if(tmp1>tmp2) top--;
else break;
}
sta[++top]=i;
}
for(int i=1;i<=top;i++)
que.push(make_pair(sta[i],n));
while(!que.empty())
{
int x=que.front().first,y=que.front().second;
que.pop();
if(vis[x][y]) continue;
vis[x][y]=ans[y]=true;
for(int i=0;i<pre[x][y].size();i++)
if(pre[x][y][i]>Mx) que.push(make_pair(x-1,pre[x][y][i]-Mx));
else que.push(make_pair(x,pre[x][y][i]));
}
for(int i=1;i<=n;i++)
printf("%lld",ans[i]);
return 0;
}

7.26考试总结(NOIP模拟24)[matrix·block·graph]的更多相关文章

  1. 2021.9.26考试总结[NOIP模拟62]

    T1 set 从\(0\)到\(n\)前缀余数有\(n+1\)个,但只有\(n\)种取值,找到一样的两个输出区间即可. \(code:\) T1 #include<bits/stdc++.h&g ...

  2. NOIP 模拟 $24\; \rm block$

    题解 \(by\;zj\varphi\) 因为它要求大于它的且放在它前的数的个数要小于它的 \(key\) 值,所以先按 \(\rm val\) 值排序,然后按 \(\rm key\) 值排序,按顺序 ...

  3. 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]

    6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...

  4. 5.23考试总结(NOIP模拟2)

    5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...

  5. 5.22考试总结(NOIP模拟1)

    5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...

  6. 2021.9.17考试总结[NOIP模拟55]

    有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...

  7. HZOJ 20190818 NOIP模拟24题解

    T1 字符串: 裸的卡特兰数题,考拉学长讲过的原题,就是bzoj3907网格那题,而且这题更简单,连高精都不用 结论$C_{n+m}^{n}-C_{n+m}^{n+1}$ 考场上10min切掉 #in ...

  8. [考试总结]noip模拟23

    因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...

  9. [考试总结]noip模拟26

    首先看到这样中二的题目心头一震.... 然而发现又是没有部分分数的一天. 然而正解不会打.... 那还是得要打暴力. 但是这套题目有两个题目只有一个参数. 所以... (滑稽).jpg 然后我就成功用 ...

  10. 2021.7.28考试总结[NOIP模拟26]

    罕见的又改完了. T1 神炎皇 吸取昨天三个出规律的教训,开场打完T2 20pts直接大力打表1h. 但怎么说呢,我不懂欧拉函数.(其实exgcd都忘了 于是只看出最大平方因子,不得不线性筛,爆拿60 ...

随机推荐

  1. sql 语句系列(行与列处理)[八百章之第一章]

    排序时对null进行处理 比如说: select * from EMP order by COMM 我需要对红框部分进行desc处理,也就是从大到小排列. 解析: 重点是如何让null独立出去. se ...

  2. 重新点亮linux 命令树————用户和用户组的配置文件[八]

    前言 简单整理一下 正文 首先看下vim /etc/passwd 这个东西. 可以看到这些就是我们的用户表. 刚才我们创建的user1就在末尾了. 那么下面有这个x:1001:1001 这个是什么意思 ...

  3. 如何使用Plotly和Dash进行数据可视化

    本文分享自华为云社区<从数据到部署使用Plotly和Dash实现数据可视化与生产环境部署>,作者: 柠檬味拥抱. 数据可视化是数据分析中至关重要的一环,它能够帮助我们更直观地理解数据并发现 ...

  4. chrome浏览器代理插件SwitchyOmega使用

    第一步:下载SwitchyOmega插件 Proxy_SwitchyOmega_2.5.21.crx 第二步:安装插件, 1,在chrome扩展程序开启开发者模式: 2,将插件拖过来: 第三步:设置代 ...

  5. Webpack中常见的Loader?解决了什么问题?

    一.是什么 loader 用于对模块的源代码进行转换,在 import 或"加载"模块时预处理文件 webpack做的事情,仅仅是分析出各种模块的依赖关系,然后形成资源列表,最终打 ...

  6. 力扣306(java)-累加数(中等)

    题目: 累加数 是一个字符串,组成它的数字可以形成累加序列. 一个有效的 累加序列 必须 至少 包含 3 个数.除了最开始的两个数以外,序列中的每个后续数字必须是它之前两个数字之和. 给你一个只包含数 ...

  7. Timing:在线自习室快速搭建

    ​通过超低延迟的音视频通信技术.视频连麦.弱网传输算法,快速搭建自习场景,提升自习效率. 客户简介 ​ 氪细胞主打产品Timing,是国内最早推出,也是规模最大的在线自习室,是新一代的教育与社交融合平 ...

  8. HBase读链路分析

    ​简介:HBase的存储引擎是基于LSM-Like树实现的,更新操作不会直接去更新数据,而是使用各种type字段(put,delete)来标记一个新的多版本数据,采用定期compaction的形式来归 ...

  9. Maxcompute造数据-方法详解

    简介: 造一点模拟数据的方法 概述 造数据在一些奇怪的场合会被用到.一般我们是先有数据才有基于数据的应用场合,但是反过来如果应用拿到另外一个场景,没有数据功能是没有方法演示的.一般较为真实的数据,脱敏 ...

  10. CPU Burst有副作用吗?让数学来回答!| 龙蜥技术

    ​简介: 使用CPU Burst的副作用是什么?是否有不适用的场景呢?戳我给你答案~ 编者按:CPU Burst 特性已合入 Linux 5.14,Anolis OS 8.2.Alibaba Clou ...