牛客NOIP暑期七天营-提高组3

比赛链接

官方题解

A-破碎的矩阵

题目描述 link

题解

标签:推结论+快速幂

挺妙的一道题??比赛的时候想到了但不敢确定正确性。

首先很容易想到,对于一个二进制数它的每一位都是独立的。那么下面的结论对于\(x=1\)和\(x=2^{30}-1\)和\(2^{60}-1\)这三组都同样适用。

大致思路就是对于一个\(n*m\)的矩阵,它左上角的子矩阵\((n-1)*(m-1)\)先随便怎么填,剩下的第\(n\)行,第\(m\)列根据剩余的异或值来进行调整,那么对于子矩阵中的任意一组填法,剩下的一列一行都有且仅有一组相应的填法。那么最终答案就为\(ans=(x+1)^{(n-1)*(m-1)}\),底是\(x+1\)是因为对于子矩阵来说,每个元素的取值范围为\([0,x]\),共\(x+1\)个数。

当然大前提是该组数据有解。如何判呢,只要把每行的值异或起来,把每列的值异或起来,若两者不相等则无解,输出0。

则总的时间复杂度为\(O(case*log(nm))\)。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
ll x,mod;
ll ksm(ll r,ll d){
ll res=1;
while(d){
if(d&1)res=res*r%mod;
r=r*r%mod;d>>=1;
}
return res;
}
int main(){
int T;scanf("%d",&T);
while(T--){
scanf("%d%d%lld%lld",&n,&m,&x,&mod);
ll sx=0,sy=0;
for(int i=1;i<=n;i++){
ll w;scanf("%lld",&w);
sx^=w;
}
for(int i=1;i<=m;i++){
ll w;scanf("%lld",&w);
sy^=w;
}
if(sx!=sy){puts("0");continue;}
ll ans=ksm((x+1)%mod,1ll*(n-1)*(m-1));
printf("%lld\n",ans);
}
}

B-点与面

题目描述 link

题解

标签:树状数组裸题

就是计个数的事,感觉难度比第一题简单很多。。

维护4个树状数组,然后循环一遍边计数边往上加就完事了,注意顺序应该是从\(5->4->3->2->1\)不然可能会出现重复计数。

时间复杂度为\(O(NlogN)\)。

代码

#include<bits/stdc++.h>
using namespace std;
#define debug(x) cout<<"### "<<x<<endl;
#define For(a,b,c) for(int a=b;a<=c;++a)
#define Dor(a,b,c) for(int a=b;a>=c;--a)
typedef long long ll;
const int N=1e5+10;
const ll mod=998244353;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x;
}
int n,num,a[N],b[N];
ll c[5][N];
inline ll askA(int x,int id){
ll res=0;
while(x){
res+=c[id][x],res%=mod;
x-=x&(-x);
}
return res;
}
inline ll askB(int x,int id){
ll res=0;
while(x<=num){
res+=c[id][x],res%=mod;
x+=x&(-x);
}
return res;
}
inline void addA(int x,ll d,int id){
while(x<=num){
c[id][x]+=d,c[id][x]%=mod;
x+=x&(-x);
}
}
inline void addB(int x,ll d,int id){
while(x){
c[id][x]+=d,c[id][x]%=mod;
x-=x&(-x);
}
}
int main(){
n=read();
for(int i=1;i<=n;i++)a[i]=read(),b[i]=a[i];
sort(b+1,b+n+1);
num=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+num+1,a[i])-b+1;
num++;
ll ans=0;
for(int i=1;i<=n;i++){
//5
ll tmp=askA(a[i]-1,4)%mod;
ans+=tmp,ans%=mod;
//4
tmp=askB(a[i]+1,3)%mod;
addA(a[i],tmp,4);
//3
tmp=askA(a[i]-1,2)%mod;
addB(a[i],tmp,3);
//2
tmp=askB(a[i]+1,1)%mod;
addA(a[i],tmp,2);
//1
addB(a[i],1,1);
}
printf("%lld\n",ans%mod);
}

C-信息传递

题目描述 link

题解

标签:断环为链+线段树区间维护最值+倍增

算法一:

适用于:60%数据,\(li,ri<=n<=10^3\)。

构图:很容易想到将问题转化为图上的最短路。对于某个人\(i\),它的传播范围为\([li,ri]\),我们由\(i\)向这个区间的所有点连一条边;

计算:对于每个点\(i\),我们以其为源点跑一遍Dijkstra求出单源最短路,然后再枚举n个点,找出其中最远的距离\(dis_j\),这个值就是答案。

时间复杂度为\(O(N^2logN)\)。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
bool nc1;
inline int read(){}
int id[2*N],n;
namespace p60{
bool f[1010][1010];
int dis[1010],vis[1010];
vector<int>e[1010];
struct node{
int w,now;
inline bool operator <(const node &x)const{
return w>x.w;
}
};
priority_queue<node>q;
void dijkstra(int s){
for(register int i=1;i<=n;i++)dis[i]=n,vis[i]=0;
dis[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(register int i=0;i<e[u].size();i++){
int v=e[u][i];
if(dis[v]>dis[u]+1){
dis[v]=dis[u]+1;
q.push((node){dis[v],v});
}
}
}
}
void solve(){
for(register int i=1;i<=n;i++){
int l=read();
for(register int j=i+n-1;j>=i+n-l;j--)if(!f[id[i]][id[j]]){
f[id[i]][id[j]]=1;
e[id[i]].push_back(id[j]);
}
}
for(register int i=1;i<=n;i++){
int r=read();
for(register int j=i+1;j<=i+r;j++)if(!f[id[i]][id[j]]){
f[id[i]][id[j]]=1;
e[id[i]].push_back(id[j]);
}
}
for(register int i=1;i<=n;i++){
int ans=0;
dijkstra(i);
for(register int j=1;j<=n;j++)if(dis[j]>ans)ans=dis[j];
printf("%d ",ans);
}
}
}
int li[N],ri[N];
bool nc2;
int main(){
n=read();
for(int i=1;i<=n;i++)id[i]=id[i+n]=i;
if(n<=1000){
p60::solve();
return 0;
}
}

算法二:

适用于:100%数据,\(li,ri<=n<=10^5\)。

首先断环为链,开三倍数组。

我们发现对于每一秒的传递,\(i\)能传到的最左边的人要么不变要么更左,\(i\)能传到的最右边的人要么不变要么更右。并且,[最左的人,最右的人]这一段区间里的所有人在此时都已经收到消息了。

根据这个单调性,我们可以维护两个数组\(li[x][i],ri[x][i]\),表示在\(2^i\)秒时,\(x\)能传递到的最左最右的人,看出用了倍增吧,那么询问时也可以利用倍增跳来快速找出答案。

接下来的任务就是如何维护呢——官方题解中给出了ST表维护最值,下面的代码中用的是线段树。

对于树上的节点\(o\)我们维护两个数组\(b[o][t][0/1]\),表示在\(2^t\)秒内节点\(o\)包括的范围\([l,r]\)中,能跳的最左,能跳的最右。

接下来一个时间一个时间的转移维护,查询时也是在树上进行的。

总的时间复杂度为\(O(Nlog^2N)\)

详见代码8:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x;
}
const int N=3e5+10;
int n,li[N][18],ri[N][18];
int b[N<<2][18][2];
int limL,limR,k,len;
void build(int o,int l,int r){
if(l==r){
b[o][k][0]=li[l][k];
b[o][k][1]=ri[l][k];
return;
}
int mid=l+r>>1;
build(o<<1,l,mid),build(o<<1|1,mid+1,r);
b[o][k][0]=min(b[o<<1][k][0],b[o<<1|1][k][0]);
b[o][k][1]=max(b[o<<1][k][1],b[o<<1|1][k][1]);
}
void query(int o,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr){
limL=min(limL,b[o][k][0]);
limR=max(limR,b[o][k][1]);
return;
}
int mid=l+r>>1;
if(ql<=mid)query(o<<1,l,mid,ql,qr);
if(qr>mid)query(o<<1|1,mid+1,r,ql,qr);
}
int main(){
n=read();len=3*n;
for(register int i=1;i<=n;i++){
int x=read();
for(register int j=i;j<=len;j+=n)li[j][0]=max(1,j-x);
}
for(register int i=1;i<=n;i++){
int x=read();
for(register int j=i;j<=len;j+=n)ri[j][0]=min(3*n,j+x);
}
if(n==1){puts("0");return 0;}
build(1,1,len); for(k=1;k<=17;k++){
for(register int i=1;i<=len;i++){
limL=1e9,limR=0;
k--;
query(1,1,len,li[i][k],ri[i][k]);
k++;
li[i][k]=limL,ri[i][k]=limR;
}
build(1,1,len);
} for(register int i=n+1;i<=n+n;i++){
int l=i,r=i,ans=0;
for(k=17;k>=0;k--){
limL=1e9,limR=0;
query(1,1,len,l,r);
if(limR-limL+1>=n)continue;
l=limL,r=limR,ans+=1<<k;
}
printf("%d ",ans+1);
}
}

牛客NOIP暑期七天营-TG3 赛后题解的更多相关文章

  1. 牛客NOIP暑期七天营-TG1 赛后题解

    目录 牛客NOIP暑期七天营-提高组1 A-最短路 题目描述 link 题解 代码 B-最小生成链 题目描述 link 题解 代码 C-最小字典最短路 题目描述 link 题解 Update 牛客NO ...

  2. 牛客NOIP暑期七天营-提高组1

    牛客NOIP暑期七天营-提高组1 链接 A 边权可为0就排序建一条链子. 但是边权不为0 除了第一个有0的不行. x连向上一个比他小的数. 期间判断有无解. #include <bits/std ...

  3. 牛客NOIP暑期七天营-普及组2D

    链接:https://ac.nowcoder.com/acm/contest/926/D来源:牛客网 在一维坐标系中,给定 n条有颜色的线段,第 i条线段的左右端点分别为 li​和 ri​,此外它的颜 ...

  4. 牛客NOIP暑期七天营-提高组6

    目录 A-积木大赛 题目描述 link 题解 代码 B-破碎的序列 题目描述 link 题解 C-分班问题 题目描述 link 题解 比赛链接 官方题解 A-积木大赛 题目描述 link 题解 标签: ...

  5. 牛客NOIP暑期七天营-提高组5+普及组5

    ————提高组———— 第一题:deco的abs 题目链接:https://ac.nowcoder.com/acm/contest/934/A 因为每个数都可以加任意次 d ,所以可以推出 0 < ...

  6. 牛客NOIP暑期七天营-提高组3

    第一题:破碎的矩阵 题目链接:https://ac.nowcoder.com/acm/contest/932/A    刚看到这题的时候感觉特别熟悉...诶,这不就是codeforces某场比赛的某某 ...

  7. 牛客NOIP暑期七天营-提高组2

    第一题:ACGT 题目链接:https://ac.nowcoder.com/acm/contest/931/A trie树.hash.map遍历  ①.trie树上的节点多记一个rest值表示还有多少 ...

  8. 牛客NOIP暑期七天营-提高组6C:分班问题 (组合数)

    题意:A班有N个人,B班有M个人,现在要组成一个新的班级C班,为了公平,从AB班各抽相同人数的人. 现在求所有方案中,人数之和是多少. 思路:即求Σ k*C(N,k)*C(M,k);    先忽略这个 ...

  9. 牛客NOIP暑期七天营-提高组5

    A:deco的abs. 水题,先%,然后相邻两个数min()一下差值. #include<bits/stdc++.h> #define ll long long using namespa ...

随机推荐

  1. AndroidStudio WiFi调试插件

    前言 此篇博客也是Android studio插件篇的一部分,后续有时间我会介绍更多AndroidStudio的插件方便开发. Android设备用WiFi调试在以前一般是通过adb连接的,但是这样的 ...

  2. css---7自定义字体

    1.Adobe illustrator AI是一种应用于出版.多媒体和在线图像的工业标准矢量插画的软件,是一款非常好的矢量图形处理工具. 该软件主要应用于印刷出版.海报书籍排版.专业插画.多媒体图像处 ...

  3. leetcode-第10周双周赛-5081-歩进数

    题目描述: 自己的提交:参考全排列 class Solution: def countSteppingNumbers(self, low: int, high: int) -> List[int ...

  4. SQL Server install

    { https://www.cnblogs.com/ios9/p/9527939.html https://www.cnblogs.com/ios9/p/9527815.html //在安装工具中 安 ...

  5. 重磅发布: 阿里云WAF日志实时分析上线 (含视频)

    摘要: 阿里云WAF与日志服务打通,对外开发Web访问与攻击日志.提供近实时的网站具体的日志自动采集存储.并提供基于日志服务的查询分析.报表报警.下游计算对接与投递的能力. 背景 Web攻击形势 互联 ...

  6. Redis-GEO

    一. Redis的GEO特性 Redis3.2版本提供了GEO功能,支持存储地理位置信息用来实现诸如摇一摇,附近位置这类依赖于地理位置信息的功能.二. 命令2.1 增加地理位置信息 命令:geoadd ...

  7. c#读取并异步写入文件,简单版,指定编码,保持原格式。

    1.同步读取和写入 StreamReader objReader = new StreamReader("E://workspace//zzz//read.txt", Encodi ...

  8. 获取AndroidManifest.xml中的meta-data元素

    android 开发中: 在AndroidManifest.xml中,<meta-data>元素可以作为子元素, 被包含在<activity>.<application& ...

  9. 豌豆荚Redis集群方案:Codis

    Codis简介 Codis是一个分布式Redis解决方案,对于上层的应用来说,连接到CodisProxy和连接原生的RedisServer没有明显的区别(不支持的命令列表),上层应用可以像使用单机的R ...

  10. 第二周课堂笔记2th

    ---恢复内容开始--- 1. 2.索引取单个值 取多个值叫切片, 切片:取多个值 从左到右取值: 原则:顾头不顾尾 1, a[0:3] abc 2, a[-5:-2] abc 3, a[0:-2] ...