牛客NOIP暑期七天营-TG3 赛后题解
牛客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 赛后题解的更多相关文章
- 牛客NOIP暑期七天营-TG1 赛后题解
目录 牛客NOIP暑期七天营-提高组1 A-最短路 题目描述 link 题解 代码 B-最小生成链 题目描述 link 题解 代码 C-最小字典最短路 题目描述 link 题解 Update 牛客NO ...
- 牛客NOIP暑期七天营-提高组1
牛客NOIP暑期七天营-提高组1 链接 A 边权可为0就排序建一条链子. 但是边权不为0 除了第一个有0的不行. x连向上一个比他小的数. 期间判断有无解. #include <bits/std ...
- 牛客NOIP暑期七天营-普及组2D
链接:https://ac.nowcoder.com/acm/contest/926/D来源:牛客网 在一维坐标系中,给定 n条有颜色的线段,第 i条线段的左右端点分别为 li和 ri,此外它的颜 ...
- 牛客NOIP暑期七天营-提高组6
目录 A-积木大赛 题目描述 link 题解 代码 B-破碎的序列 题目描述 link 题解 C-分班问题 题目描述 link 题解 比赛链接 官方题解 A-积木大赛 题目描述 link 题解 标签: ...
- 牛客NOIP暑期七天营-提高组5+普及组5
————提高组———— 第一题:deco的abs 题目链接:https://ac.nowcoder.com/acm/contest/934/A 因为每个数都可以加任意次 d ,所以可以推出 0 < ...
- 牛客NOIP暑期七天营-提高组3
第一题:破碎的矩阵 题目链接:https://ac.nowcoder.com/acm/contest/932/A 刚看到这题的时候感觉特别熟悉...诶,这不就是codeforces某场比赛的某某 ...
- 牛客NOIP暑期七天营-提高组2
第一题:ACGT 题目链接:https://ac.nowcoder.com/acm/contest/931/A trie树.hash.map遍历 ①.trie树上的节点多记一个rest值表示还有多少 ...
- 牛客NOIP暑期七天营-提高组6C:分班问题 (组合数)
题意:A班有N个人,B班有M个人,现在要组成一个新的班级C班,为了公平,从AB班各抽相同人数的人. 现在求所有方案中,人数之和是多少. 思路:即求Σ k*C(N,k)*C(M,k); 先忽略这个 ...
- 牛客NOIP暑期七天营-提高组5
A:deco的abs. 水题,先%,然后相邻两个数min()一下差值. #include<bits/stdc++.h> #define ll long long using namespa ...
随机推荐
- CSS3——动画
动画是CSS3中具有颠覆性的特征之一,可通过设置多个节点来精确控制一个或一组动画,常用来实现复杂的动画效果. 语法格式: animation:动画名称 动画时间 运动曲线 何时开始 播放次数 是否反 ...
- R语言 数据重塑
R语言数据重塑 R语言中的数据重塑是关于改变数据被组织成行和列的方式. 大多数时间R语言中的数据处理是通过将输入数据作为数据帧来完成的. 很容易从数据帧的行和列中提取数据,但是在某些情况下,我们需要的 ...
- Responder对象
Responder对象 响应者是一个对象,它可以响应事件并处理它们.所有响应者对象是类的,最终从UIResponder的( IOS)或NSResponder ( OS X)继承实例.这些类声明一个编程 ...
- 牛客多校第六场 E Androgynos 自补图
题意: 给定点数,构造自补图,要求输出邻接矩阵,和原图与补图的同构映射. 题解: 只有点数为4k和4k+1的情况才能构造自补图,因为只有这些情况下边数才为偶数. 一种构造方式是,邻接矩阵和同构映射增量 ...
- Linux课程---15、域名相关
Linux课程---15.域名相关 一.总结 一句话总结: 先购买域名,再备案,再解析,域名即可使用 1.域名备案是怎么回事(比如二级域名,三级域名)? 每个二级域名需要备案一次,三级域名不需要备案, ...
- 使用SharpZipLib实现zip压缩
使用国外开源加压解压库ICSharpCode.SharpZipLib实现加压,该库的官方网站为http://www.icsharpcode.net/OpenSource/SharpZipLib/D ...
- 为什么程序员都不喜欢使用switch,而是大量的 if……else if ?
作者:熊爸爸 原文:http://3g.163.com/tech/article/E02RDE6C0511SDDL.html 请用5秒钟的时间查看下面的代码是否存在bug. OK,熟练的程序猿应该已经 ...
- ZOJ-1107-FatMouse and Cheese-dfs+记忆化搜索
FatMouse has stored some cheese in a city. The city can be considered as a square grid of dimension ...
- java web项目部署到云服务器
第一步把java web项目打包 成war包 第二步:在Build选里选择build Artfacts->water:war->Build war包建立完毕. 第三步:在官网下载winsc ...
- Font Awesome 完全兼容 Bootstrap 的所有组件。
"F_FullName": "其他", "F_Icon": "glyphicon glyphicon-backward fa-lg ...