2019-2020Nowcoder Girl初赛 题解
Posted echozqn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019-2020Nowcoder Girl初赛 题解相关的知识,希望对你有一定的参考价值。
题目都不是很难,就是最后一题有点毒瘤
第一题:牛妹爱整除
这个你把一个进制数进行拆分,拆分成若干位,然后在取模,这样会发现如果是x进制的数,那么对x+1这个进制转化即满足条件。
举个例子:一个x进制数abc a*x*x+b*x+c
那么(a*x*x+b*x+c)%k 满足于 (a+b+c) 相等
则x=k+1,那么x%k==1 所以 a*(x%k)*(x%k)%k+b*(x%k)%k+c%k==(a+b+c)%k
代码很简单,有需求可以直接去牛客找
第二题:吃桃
这个是一个树的题目,直接dfs就可以解决,算是dp吧。
首先dfs找到深度,然后在找深度的同时把路径记录下来,最后输出,
为了保证小的先选可以先拍个序。
第三题:背包问题
这个是一个很裸的背包。
dp[j]表示价值为 j 的物品,可以占的最多的背包体积
第四题:泡面
不知道自己怎么就过了,之前cf有一个差不多的题目(我之前以为差不多),后来发现是两个不一样的题目。
但是比赛的时候并没有发现,然后我按照我的印象写了,居然A了,因为我写出bug了,但是这个bug好像很合适这个题目,谜之A了。。。
赛后重新写了一次。
这个就是一个模拟,用个优先队列模拟就可以了。
注意开longlong
#include <bits/stdc++.h> #define inf 0x3f3f3f3f using namespace std; const int maxn=1e5+5; typedef long long ll; struct node{ ll id,val; node(ll id=0,ll val=0):id(id),val(val){} bool operator<(const node &a)const{ return a.id<id; } }a[maxn]; bool cmp(node a,node b){ return a.val<b.val; } priority_queue<node>que; ll ans[maxn]; int main(){ ll n,p,x; scanf("%lld%lld",&n,&p); for(int i=1;i<=n;i++) { scanf("%lld",&x); a[i]=node(i,x); } sort(a+1,a+1+n,cmp); ll nowtime=a[1].val,now=2; while(!que.empty()) que.pop(); que.push(a[1]); while(!que.empty()){ nowtime+=p; node u=que.top();que.pop(); ans[u.id]=nowtime; while(now<=n&&a[now].val<=nowtime){ que.push(a[now]); now++; } if(que.empty()&&now<=n){ nowtime=a[now].val; que.push(a[now]); now++; } } for(int i=1;i<=n;i++) printf("%lld ",ans[i]); printf(" "); return 0; }
cf和这个很像的题目
https://codeforces.com/contest/1248/problem/E
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <map> #include <iostream> #include <cstdlib> #include <stack> #define inf 0x3f3f3f3f #define LL long long #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int maxn = 1e5 + 10; struct node{ int id; ll tim; node(int id=0,ll tim=0):id(id),tim(tim){} bool operator<(const node&a)const{ return a.id<id; } }a[maxn]; queue<node>que; priority_queue<node>prique; int mins[maxn*4]; void build(int id,int l,int r){ mins[id]=inf; if(l==r) return ; int mid=(l+r)>>1; build(id<<1,l,mid); build(id<<1|1,mid+1,r); } void push_up(int id){ mins[id]=min(mins[id<<1],mins[id<<1|1]); } void update(int id,int l,int r,int pos,int val){ if(l==r){ mins[id]=val; return ; } int mid=(l+r)>>1; if(pos<=mid) update(id<<1,l,mid,pos,val); else update(id<<1|1,mid+1,r,pos,val); push_up(id); } bool cmp(node a,node b){ if(a.tim==b.tim) return a.id<b.id; return a.tim<b.tim; } ll ans[maxn]; int main(){ int n,p; scanf("%d%d",&n,&p); build(1,1,n); for(int i=1;i<=n;i++) scanf("%lld",&a[i].tim),a[i].id=i; sort(a+1,a+1+n,cmp); while(!que.empty()) que.pop(); while(!prique.empty()) prique.pop(); int now=1; ll nowtime=a[now].tim; que.push(a[now]); update(1,1,n,a[now].id,a[now].id);now++; while(now<=n&&a[now].tim<=nowtime+p){ if(a[now].id<=mins[1]) { que.push(a[now]); update(1,1,n,a[now].id,a[now].id);now++; } else prique.push(a[now]),now++; } while(now<=n||!que.empty()||!prique.empty()){ while(!prique.empty()){ node u=prique.top(); if(u.id<=mins[1]){ prique.pop(); que.push(u); update(1,1,n,u.id,u.id); } else break; } while(now<=n&&a[now].tim<=nowtime+p){ if(a[now].id<=mins[1]) { que.push(a[now]); update(1,1,n,a[now].id,a[now].id);now++; } else prique.push(a[now]),now++; } if(!que.empty()){ int u=que.front().id;que.pop(); ans[u]=nowtime+p; update(1,1,n,u,inf); } nowtime+=p; if(que.empty()&&prique.empty()&&now<=n) nowtime=a[now].tim; } for(int i=1;i<=n;i++) printf("%lld ",ans[i]); printf(" "); return 0; }
第五题:伪直径
这个题目如果你之前碰到过求直径的题目就可以很快的反应过来,但是如果没有呢,就可能需要思考一会吧。
而且这个题目名字已经给了很大的提示了,所以还是很好写的。
答案就是直径减一
怎么求直径呢?这可以从紫书上看
就是两次dfs
就是随便找一个点然后找到最深的叶子节点,然后从这个叶子节点找到最深的另一个叶子节点就可以了。
第六题:最大最小差
这个题目好毒瘤
比赛的时候没有写出来
然后赛后,用线段树+二分写了一次,tle 3分
然后问了一个oi dalao,学习了一下双指针+st表的写法,依旧tle,但是 18分
最后加了各种优化,19分 tle
最后学会了一种超级厉害的快读,终于A了,oi的快读真强。
好像还可以用单调队列+双指针写,但是好难写,我不会。。。
#include <bits/stdc++.h> #define inf 0x3f3f3f3f # define getchar() (S==T&&(T=(S=BB)+fread(BB,1,1<<20,stdin),S==T)?EOF:*S++) char BB[1 << 20], *S = BB, *T = BB; using namespace std; const int maxn=1e6+5; typedef long long ll; int maxsum[maxn][22],minsum[maxn][22],a[12][maxn],v[12],f[maxn],w[30]; void init(int n){ for(int i=1;i<maxn;i++) f[i]=(log(i*1.0)/log(2.0)); for(int i=0;i<30;i++) w[i]=(1<<i); } void RMQ(int id,int n) { for(int i=1;i<=n;i++){ maxsum[i][0]=a[id][i]; minsum[i][0]=a[id][i]; } for (int i = 1; i < 20; i++) { for (int j = 1; j <= n; j++) { if (j + w[i] - 1 <= n) { maxsum[j][i] = max(maxsum[j][i - 1], maxsum[j + w[i-1]][i - 1]); minsum[j][i] = min(minsum[j][i - 1], minsum[j + w[i-1]][i - 1]); } } } } int st(int x,int y){ int k=f[y-x+1]; int maxnum = max(maxsum[x][k], maxsum[y - w[k] + 1][k]); int minnum = min(minsum[x][k], minsum[y - w[k] + 1][k]); int ans = maxnum - minnum; return ans; } int L[maxn],R[maxn]; int read() { int x=0; char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar(); return x; } inline void write(ll X) { if (X < 0) { putchar(‘-‘); X = ~(X - 1); } int s[20], top = 0; while (X) { s[++top] = X % 10; X /= 10; } if (!top) s[++top] = 0; while (top) putchar(s[top--] + ‘0‘); putchar(‘ ‘); } int main(){ int n,t; n=read(); t=read(); init(n); for(int i=1;i<=t;i++) v[i]=read(); for(int i=1;i<=t;i++){ for(int j=1;j<=n;j++){ a[i][j]=read(); } } ll ans=0; memset(R,inf,sizeof(R)); for(int i=1;i<=t;i++){ RMQ(i,n); int p1=1,p2=1; for(int j=1;j<=n;j++){ while(p1<=j&&st(p1,j)>v[i]) p1++; while(p2+1<=j&&st(p2+1,j)>=v[i]) p2++; if(st(p1,j)!=v[i]) L[j]=inf; else L[j]=max(L[j],p1); if(st(p2,j)!=v[i]) R[j]=0; else R[j]=min(R[j],p2); } } for(int i=1;i<=n;i++){ if(L[i]<=R[i]) ans+=R[i]-L[i]+1; } // printf("%lld ",ans); write(ans); return 0; }
以上是关于2019-2020Nowcoder Girl初赛 题解的主要内容,如果未能解决你的问题,请参考以下文章