6.26考试总结(NOIP模拟10)[入阵曲·将军令·星空]
对于虚伪而言,真实的光明或许过于耀眼了
前言
这一次吧,考得特别烂,主要是这次考试想搞一下特殊性质,然后一不小心就因小失大弄巧成拙了下,下次注意吧。。
T1 入阵曲
暴力
思路
对于这个题的话,暴力的话55pts是没有问题的,无非是二维前缀和优化一下。
然后针对于特殊性质我们可以再骗到20pts,我们发现矩形是否整除 K 是与矩阵内的数字和矩形的边长是有关系的,接下来暴力扫就可以了。。
有一个比较遗憾的地方就是这个题考试的时候搞了1.5h,但是码最基础的暴力实际上只用了20min,然后对于特殊性质搞了挺长时间,主要是搞因数那一块思路错了,最后对于这个特殊性质草草地打了上面那个暴力就走了。。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=4e2+10;
int n,m,ans,temp,mod,h[N][N],z[N][N],s[N][N],t[N][N];
int cnt,ys[N];
bool flag;
void check()
{
/*
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cout<<t[i][j]<<' ';
cout<<endl;
}
// */
freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
}
inline void work(int x,int y)
{
for(int i=1;i<=x;i++)
for(int j=1;j<=y;j++)
if((t[x][y]-t[i-1][y]-t[x][j-1]+t[i-1][j-1])%mod==0)
ans++;
}
inline void solve_1()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
h[i][j]=h[i][j-1]+s[i][j];
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
z[i][j]=z[i][j-1]+s[j][i];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
t[i][j]=t[i][j-1]+z[j][i];
// check();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
work(i,j);
}
inline void solve_2()
{
if(mod%temp==0)
mod/=temp;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(i*j%mod==0)
ans+=(n-i+1)*(m-j+1);
}
#undef int
int main()
{
#define int register long long
#define ll long long
// check();
scanf("%lld%lld%lld",&n,&m,&mod);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%lld",&s[i][j]);
temp=s[1][1];
if(s[i][j]!=temp)
flag=true;
}
if(flag) solve_1();
else solve_2();
printf("%lld",ans);
return 0;
}
正解
思路
对于正解就是在先前暴力的思路上优化,发现在\(\bmod k\)的意义下相同的前缀和任意取两个枚举相减一定是 k 的倍数了。
因此我们枚举每一行以及他下面的行,然后再枚举列,对于不同的\(\bmod k\)余数记录并且更新就好了,最后注意清空就好了。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=4e2+10,M=1e6+10;
int n,m,ans,mod,cnt[M],tmp[N],z[N][N],s[N][N],t[N][N];
inline void init()
{
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
z[i][j]=z[i][j-1]+s[j][i];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
t[i][j]=(t[i][j-1]+z[j][i])%mod;
}
#undef int
int main()
{
#define int register long long
#define ll long long
scanf("%lld%lld%lld",&n,&m,&mod);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%lld",&s[i][j]);
init();
for(int i=0;i<n;i++)
for(int j=i+1;j<=n;j++)
{
cnt[0]=1;
for(int k=1;k<=m;k++)
{
tmp[k]=(t[j][k]-t[i][k]+mod)%mod;
ans+=cnt[tmp[k]];
cnt[tmp[k]]++;
}
for(int k=1;k<=m;k++)
cnt[tmp[k]]=0;
}
printf("%lld",ans);
return 0;
}
T2 将军令
暴力
思路
其实吧,这个题比上一个题还要遗憾。。
对于本题的暴力,直接dfs就好,但是考试的时候一开始想的是在树上直接进行的dfs,然后发现深度搜索好像压根就不行。。。
于是我们用将近1h换来了几乎0pts,然后考虑更改dfs思路。
想到一个比较妙的方法,我们不是在树上进行dfs,而是对于可以覆盖到的驿站,以及有小队的驿站的数量进行深搜,然后对于每一个没有过小队的点进行尝试。
- 注意:一定要在加小队的同时,扩散可以覆盖到的驿站,并及时进行回溯,不然就会5pts(code)
然后我们考虑特殊性质,发现对于所有节点到1距离不超过2的情况我们直接在1节点加入小队,在有子节点的深度为1的节点处加小队就好了。
暴力+特殊性质共计50pts。
当然,如果你打过小胖守皇宫这个题的话,对于k=1的情况也是50pts(反正我是一点都不记得了。。)
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10,M=N<<1,INF=1e9;
int n,m,ans=INF,task,dep[N],f[N][20];
vector<int> v[N];
bool vis[N],vis1[N];
struct Edge
{
int tot,head[N],nxt[M],ver[M];
void add(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
}e;
void check()
{
freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
}
void dfs(int x,int fa)
{
dep[x]=dep[fa]+1;
f[x][0]=fa;
for(int i=0;f[x][i];i++)
f[x][i+1]=f[f[x][i]][i];
for(int i=e.head[x];i;i=e.nxt[i])
if(e.ver[i]!=fa)
dfs(e.ver[i],x);
}
int LCA(int x,int y)
{
if(x==y)
return x;
if(dep[x]>dep[y])
x^=y^=x^=y;
for(int i=20;i>=0;i--)
if(dep[f[y][i]]>=dep[x])
y=f[y][i];
if(x==y)
return x;
for(int i=20;i>=0;i--)
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
return f[x][0];
}
int dist(int x,int y)
{
return dep[x]+dep[y]-2*dep[LCA(x,y)];
}
void dfs1(int tot,int cnt)
{
if(cnt>n)
return ;
if(tot>=n)
{
ans=min(ans,cnt);
return ;
}
if(cnt>=ans)
return ;
vector<int > vi;
for(int i=1;i<=n;i++)
{
if(vis[i])
continue;
bool temp=vis1[i];
vis[i]=vis1[i]=true;
vi.clear();
for(int j=1;j<=n;j++)
{
if(vis1[j])
continue;
for(int k=0;k<v[j].size();k++)
if(vis[v[j][k]])
{
vis1[j]=true;
tot++;
vi.push_back(j);
break;
}
}
dfs1(tot+(!temp),cnt+1);
tot-=vi.size();
vis[i]=false;
vis1[i]=temp;
for(int j=0;j<vi.size();j++)
vis1[vi[j]]=false;
}
}
void solve_1()
{
dfs(1ll,0ll);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
int dis=dist(i,j);
if(dis<=m)
{
v[i].push_back(j);
v[j].push_back(i);
}
}
dfs1(0ll,0ll);
}
void solve_2()
{
// /*
dfs(1,0);
int flag=0;
int sum=0;
for(int i=2;i<=n;i++)
if(dep[i]==2&&e.nxt[e.head[i]])
sum++;
ans=sum+1;
// */
// ans=2;
}
#undef int
int main()
{
#define int register long long
#define ll long long
scanf("%lld%lld%lld",&n,&m,&task);
for(int i=1,x,y;i<n;i++)
{
scanf("%lld%lld",&x,&y);
e.add(x,y);
e.add(y,x);
}
if(!m) ans=n;
else if(task!=2) solve_1();
else solve_2();
printf("%lld",ans);
return 0;
}
正解
思路
与消防局的设立有亿些相似。
正解是贪心,首先对于深度从大到小排序,用dis数组记录距离这个点最近的有小队的驿站的数量。
如果一个点的dis大于k,那么我们直接在他的第k级祖先加入小队,然后更新深度更小的节点的dis值就好了。
最后统计一下dis为0的节点数就是答案了。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10,M=N<<1,INF=1e9;
int n,m,ans,task,id[N],dep[N],fa[N],dis[N],f[N];
struct Edge
{
int tot,head[N],nxt[M],ver[M];
void add(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
}e;
void dfs(int x,int fat)
{
dep[x]=dep[fat]+1;
fa[x]=fat;
for(int i=e.head[x];i;i=e.nxt[i])
if(e.ver[i]!=fat)
dfs(e.ver[i],x);
}
bool comp(int x,int y)
{
return dep[x]>dep[y];
}
#undef int
int main()
{
#define int register long long
#define ll long long
scanf("%lld%lld%lld",&n,&m,&task);
fill(dis+0,dis+n+1,INF);
for(int i=1,x,y;i<n;i++)
{
scanf("%lld%lld",&x,&y);
e.add(x,y);
e.add(y,x);
}
for(int i=1;i<=n;i++)
id[i]=i;
dfs(1ll,0ll);
sort(id+1,id+n+1,comp);
for(int i=1;i<=n;i++)
{
int cnt=0,x=id[i];
if(dis[x]<=m)
continue;
f[0]=x;
while(cnt<m&&f[cnt])
{
f[cnt+1]=fa[f[cnt]];
cnt++;
if(f[cnt])
dis[x]=min(dis[x],dis[f[cnt]]+cnt);
}
if(!f[cnt])
cnt=max(cnt-1,0ll);
if(dis[x]>m)
{
dis[f[cnt]]=0;
int fat=f[cnt],sum=0;
while(fat&&sum<=m)
{
dis[fat]=min(dis[fat],sum);
fat=fa[fat];
sum++;
}
}
}
for(int i=1;i<=n;i++)
if(!dis[i])
ans++;
printf("%lld",ans);
return 0;
}
T3 星空
解题思路
对于暴力就不多讲了,骗一下\(ans \le 4\)的分就好了,多了也骗不到。。
正解思路非常妙,官方的题解上说需要差分,但是个人感觉和差分关系下不大,无非是处理一下开关状态不同的边界,然后记录罢了。
其实如果时间允许的话我们可以通过bfs求出任意一点与其他点之间变成统一状态的最小操作次数。
但是我们发现所有真正有用的点只有\(2\times k\)个,所以只要bfs这几个点求出到其他点的距离就可以了。
然后由于k的数据比较小,我们直接对于k进行状压就好了,暴力枚举每一个边界点然后更新f数组,最后的满状态的就是ans了。
code
#include<bits/stdc++.h>
using namespace std;
const int N=4e4+10,M=18,K=70.,INF=1061109567;
int n,m,cnt,k,dis[M][N],len[K],f[1<<M],tmp[M];
bool s[N];
queue<int > q;
void bfs(int pos,int val)
{
dis[pos][val]=0;
q.push(val);
while(!q.empty())
{
int num=q.front();
q.pop();
for(int i=1;i<=m;i++)
{
if(num-len[i]>=0&&dis[pos][num-len[i]]>dis[pos][num]+1)
{
dis[pos][num-len[i]]=dis[pos][num]+1;
q.push(num-len[i]);
}
if(num+len[i]<=n&&dis[pos][num+len[i]]>dis[pos][num]+1)
{
dis[pos][num+len[i]]=dis[pos][num]+1;
q.push(num+len[i]);
}
}
}
}
int get_first(int state)
{
int sum=0;
while(!(state&(1<<sum)))
sum++;
return sum;
}
int work(int state)
{
if(f[state]!=INF)
return f[state];
if(!state)
return 0;
int pos=get_first(state);
for(int i=pos+2;i<=cnt;i++)
if(state&(1<<(i-1)))
f[state]=min(f[state],work(state^(1<<pos)^(1<<(i-1)))+dis[pos+1][tmp[i]]);
return f[state];
}
int main()
{
scanf("%d%d%d",&n,&k,&m);
memset(dis,0x3f,sizeof(dis));
memset(f,0x3f,sizeof(f));
for(int i=1,x;i<=k;i++)
{
scanf("%d",&x);
s[x]=true;
}
for(int i=1;i<=m;i++)
scanf("%d",&len[i]);
for(int i=0;i<=n;i++)
if(s[i]!=s[i+1])
tmp[++cnt]=i;
for(int i=1;i<=cnt;i++)
bfs(i,tmp[i]);
printf("%d",work((1<<cnt)-1));
return 0;
}
6.26考试总结(NOIP模拟10)[入阵曲·将军令·星空]的更多相关文章
- noip模拟10[入阵曲·将军令·星空](luogu)
对于这次考试来说,总体考得还是不错的 就是有一个小问题,特判一定要判对,要不然和不判一样,甚至错了还会挂掉30分 还有一个就是时间分配问题,总是在前几个题上浪费太多时间,导致最后一个题完全没有时间思考 ...
- [考试总结]noip模拟10
不小心有咕掉了一段时间 这次考试咕掉的分数也是太多了 然后就是这次暴力完全没有打满 遗憾啊遗憾 T1 入阵曲 前面的题目背景故意引导我们去往矩阵快速幂的方向去想 然而半毛钱关系没有 其实就是维护前缀和 ...
- 2021.6.29考试总结[NOIP模拟10]
T1 入阵曲 二位前缀和暴力n4可以拿60. 观察到维护前缀和时模k意义下余数一样的前缀和相减后一定被k整除,前缀和维护模数,n2枚举行数,n枚举列, 开一个桶记录模数出现个数,每枚举到该模数就加上它 ...
- 2021.9.26考试总结[NOIP模拟62]
T1 set 从\(0\)到\(n\)前缀余数有\(n+1\)个,但只有\(n\)种取值,找到一样的两个输出区间即可. \(code:\) T1 #include<bits/stdc++.h&g ...
- 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]
6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...
- 5.23考试总结(NOIP模拟2)
5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...
- 5.22考试总结(NOIP模拟1)
5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- [考试总结]noip模拟23
因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...
- 2021.8.13考试总结[NOIP模拟38]
T1 a 入阵曲.枚举矩形上下界,之后从左到右扫一遍.用树状数组维护前缀和加特判可以$A$,更保险要脸的做法是双指针扫,因为前缀和单调不减. $code:$ 1 #include<bits/st ...
随机推荐
- leetcode - 子数组最大平均值
给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. 示例: 输入:[1,12,-5,-6,50,3], k = 4 输出:12.75 解释:最大平均数 (12-5-6+5 ...
- 使用Quorum Journal Manager(QJM)的HDFS NameNode高可用配置
前面的一篇文章写到了hadoop hdfs 3.2集群的部署,其中是部署的单个namenode的hdfs集群,一旦其中namenode出现故障会导致整个hdfs存储不可用,如果是要求比较高的集群,有必 ...
- 顺通鞋业ERP管理系统
鞋业管理软件/鞋业管理系统/鞋业管理云平台 顺通鞋业ERP进销存系统拥有订货管理.销售管理.财务管理.产品管理.库存管理.客户管理.员工管理.查询统计等功能.顺通鞋业ERP进销存系统在管理信息系统业务 ...
- kubelet 原理分析
Reference https://atbug.com/kubelet-source-code-analysis/ kubelet 简介 kubernetes 分为控制面和数据面,kubelet 就是 ...
- ArcPy自动绘制大量地图并设置地图要素:Python
本文介绍基于Python语言中ArcPy模块,实现ArcMap自动批量出图,并对地图要素进行自定义批量设置的方法. 1 任务需求 首先,我们来明确一下本文所需实现的需求. 现有通过Pyth ...
- 浅谈DDD中的聚合
简介: 在我看来并不是MVC的基础上增加领域层,使用充血模型,解耦基础服务,我的代码就符合DDD了. 作者 | 李宇飞(菜尊)来源 | 阿里开发者公众号 在我看来并不是MVC的基础上增加领域层,使用充 ...
- 为什么游戏行业喜欢用PolarDB
简介: PolarDB 在游戏行业的最佳实践 为什么游戏行业喜欢用PolarDB 游戏行业痛点 在我看来, 不同行业对数据库使用有巨大的差别. 比如游戏行业没有复杂的事务交易场景, 他有一个非常大的b ...
- 一文读懂容器存储接口 CSI
简介: 在<一文读懂 K8s 持久化存储流程>一文我们重点介绍了 K8s 内部的存储流程,以及 PV.PVC.StorageClass.Kubelet 等之间的调用关系.接下来本文将将重点 ...
- WebAssembly + Dapr = 下一代云原生运行时?
简介: 云计算已经成为了支撑数字经济发展的关键基础设施.云计算基础设施也在持续进化,从 IaaS,到容器即服务(CaaS),再到 Serverless 容器和函数 PaaS (fPaaS 或者 Faa ...
- Kettle on MaxCompute使用指南
简介: Kettle是一款开源的ETL工具,纯java实现,可以运行于Windows, Unix, Linux上运行,提供图形化的操作界面,可以通过拖拽控件的方式,方便地定义数据传输的拓扑.Kett ...