2020年牛客算法入门课练习赛3 (A bfs B 容斥 C 线段树+主席树 D 暴力最短路 E 思维构造 )
2020-07-01 16:10
375 查看
钉钉、微博极速扩容黑科技,点击观看阿里云弹性计算年度发布会!>>>
昨晚 div3 A 出了 最后一题,只有100左右人 A 的题有点兴奋 玩到2点,中午没睡着,傍晚吃了一颗维生素C(助睡眠)睡了20分钟,扛着迷迷糊糊的大脑来打这场。然后就没打好,四个题都会写,就是A题找bug浪费n久。导致赛时2题,赛后半小时又两题
A-胖胖的牛牛
做法:经典bfs水题了。不会的去面壁,萌新除外
#pragma GCC optimize(2) #include<bits/stdc++.h> #define ll long long #define maxn 1005 #define inf 1e9 #define pb push_back #define rep(i,a,b) for(int i=a;i<=b;i++) #define per(i,a,b) for(int i=a;i>=b;i--) using namespace std; inline ll read() { ll x=0,w=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();} while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();} return w==1?x:-x; } const int N=1e2+10; char s ; int n; ll vis ; int si,sj,ei,ej; struct node { int x,y; ll w; int id; bool operator <(const node &o)const { return w>o.w; } }; int dir[4][2]={1,0,0,1,-1,0,0,-1}; void bfs() { priority_queue<node>que; rep(i,1,n) rep(j,1,n) vis[i][j]=1e9;vis[si][sj]=0; que.push({si,sj,0,-1}); while(que.size()) { node now=que.top();que.pop(); //printf("x:%d y:%d w:%d id:%d\n",now.x,now.y,now.w,now.id); if(now.x==ei&&now.y==ej){printf("%lld\n",now.w);return ;} for(int i=0;i<4;++i){ int x=now.x+dir[i][0]; int y=now.y+dir[i][1]; if(x<1||y<1||x>n||y>n||s[x][y]=='x') continue; if(now.id==-1||i==now.id){ if(vis[x][y]>=now.w){ vis[x][y]=now.w; que.push({x,y,vis[x][y],i}); } } else{ int w=1; if(abs(now.id-i)==2) w=2; if(vis[x][y]>=now.w+w){ vis[x][y]=now.w+w; que.push({x,y,vis[x][y],i}); } } } } puts("-1"); } int main() { cin>>n; rep(i,1,n) rep(j,1,n) { cin>>s[i][j]; if(s[i][j]=='A') si=i,sj=j; if(s[i][j]=='B') ei=i,ej=j; } if(si==0||sj==0||ei==0||ej==0){puts("-1");return 0;} bfs(); // rep(i,1,n) { // rep(j,1,n) printf("%d ",vis[i][j]); // puts(""); // } } /* 6 A . x x x x . . . . . x x . x x . x x . . x x x x x . . . x x x x x B x */
B-牛牛的零食
做法:数据: n只有15,容斥一下,区间内 被8整除的个数 减去 被8整除同时被其他某个数整除的数 加上.....(奇加偶减)
由于数很大,计算多个数的LCM时需要运用唯一分解的 分解素数的方法 保存素数最大次幂
#pragma GCC optimize(2) #include<bits/stdc++.h> #define maxn 1005 #define inf 1e9 #define pb push_back #define rep(i,a,b) for(int i=a;i<=b;i++) #define per(i,a,b) for(int i=a;i>=b;i--) using namespace std; typedef long long ll; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} ll powmod(ll a,ll b) { ll res=1; for(;b;b>>=1){ if(b&1)res=res*a; a=a*a; } return res; } inline ll read() { ll x=0,w=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();} while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();} return w==1?x:-x; } const int N=20; ll a ,l,r,f ; int n,len; vector<pair<ll,ll> >num ; ll run(ll v) { //v=v/8; ll ans=0; for(int i=1;i<=len;++i){//m枚举状态 ll res=1; int num1=0; map<ll,ll>mp; for(int j=0;j<n;++j){//枚举点 if(i&f[j]){ for(auto it:num[j]) mp[it.first]=max(mp[it.first],it.second); num1++; } } int flag=1; for(auto it:mp){ res=res*powmod(it.first,it.second); if(res>v) { flag=0; break; } } if(!flag) continue; //printf("v:%lld i:%d res:%lld\n",v,i,res); ll gc=gcd(res,8); res=res*8/gc; //res=res/gc; if(num1%2) ans+=v/res; else ans-=v/res; } return ans; } int main() { n=read(); rep(i,0,n-1) a[i]=read(); f[0]=1;rep(i,1,n+1) f[i]=f[i-1]*2; rep(i,0,n-1) { ll tmp=a[i]; for(int j=2;j*j<=tmp;++j){ if(tmp%j==0){ int res=0; while(tmp%j==0) res++,tmp=tmp/j; num[i].push_back({j,res}); } } if(tmp!=1) num[i].push_back({tmp,1}); } l=read(),r=read(); len=(1<<n)-1; ll ans = r / 8 - (l - 1) / 8 - ( run(r) - run(l-1) ); printf("%lld\n",ans); }
C-牛牛的最美味和最不美味的零食
做法:eat部分不能暴力去写,这里用主席树维护每个位置是否有数,然后对2 操作的l r 查询下区间内第l 大 第r大的位置即可。
得到新的l、r即可。最大值就用普通线段树就可以了。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=(b);++i) #define per(i,a,b) for(int i=a;i>=(b);--i) #define mem(a,x) memset(a,x,sizeof(a)) #define pb push_back #define pi pair<int, int> #define mk make_pair using namespace std; typedef long long ll; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} inline ll read() { ll x=0,w=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();} while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();} return w==1?x:-x; } const int N=1e6+10,inf=1e9+10; int sum[4*N],mx[4*N],mi[4*N],n,m; void build(int id,int l,int r) { if(l==r){ scanf("%d",&mx[id]); mi[id]=mx[id]; sum[id]=1; return ; } int mid=l+r>>1; build(id<<1,l,mid); build(id<<1|1,mid+1,r); mx[id]=max(mx[id<<1],mx[id<<1|1]); mi[id]=min(mi[id<<1],mi[id<<1|1]); sum[id]=sum[id<<1]+sum[id<<1|1]; } void up(int id,int l,int r,int pos) { if(l==r){ mx[id]=-inf,mi[id]=inf;sum[id]=0; return ; } int mid=l+r>>1; if(pos<=mid) up(id<<1,l,mid,pos); else up(id<<1|1,mid+1,r,pos); mx[id]=max(mx[id<<1],mx[id<<1|1]); mi[id]=min(mi[id<<1],mi[id<<1|1]); sum[id]=sum[id<<1]+sum[id<<1|1]; } int qu1(int id,int l,int r,int k) { if(l==r) return l; int ans=0; int mid=l+r>>1; if(sum[id<<1]>=k) return qu1(id<<1,l,mid,k); return qu1(id<<1|1,mid+1,r,k-sum[id<<1]); } void qu2(int id,int l,int r,int ql,int qr,int &ans1,int &ans2) { if(ql<=l&&r<=qr){ ans1=max(ans1,mx[id]); ans2=min(ans2,mi[id]); return ; } int mid=l+r>>1; if(ql<=mid) qu2(id<<1,l,mid,ql,qr,ans1,ans2); if(qr>mid) qu2(id<<1|1,mid+1,r,ql,qr,ans1,ans2); } int main() { n=read(),m=read(); build(1,1,n); while(m--) { int ty=read(); if(ty==1){ int k=read(); int s=qu1(1,1,n,k); up(1,1,n,s); } else{ int l=read(),r=read(); l=qu1(1,1,n,l); r=qu1(1,1,n,r); int ans1=-inf,ans2=1e9; qu2(1,1,n,l,r,ans1,ans2); printf("%d %d\n",ans2,ans1); } } }
D-瘦了的牛牛去旅游
数据n<=50
做法:由于n很小,考虑计算两个点内所有长度的距离。设dp[cnt][i][j] 为i点到j点 距离为cnt的最短路。
那么floyd 不仅要枚举中间节点k 还要枚举i到k的之间的距离l 进而得出k到j的中间距离 cnt-l
跑一边5层for循环即可。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=(b);++i) #define per(i,a,b) for(int i=a;i>=(b);--i) #define mem(a,x) memset(a,x,sizeof(a)) #define pb push_back #define pi pair<int, int> #define mk make_pair using namespace std; typedef long long ll; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} inline ll read() { ll x=0,w=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();} while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();} return w==1?x:-x; } const int N=52,inf=0x3f3f3f3f; int dp ; int vis ,n,m; double ans ; int main() { n=read();m=read(); memset(dp,inf,sizeof(dp)); rep(i,1,m){ int u=read(),v=read(), w=read(); vis[u][v]=1; dp[1][u][v]=min(dp[1][u][v],w); } for(int cnt=2;cnt<=n;++cnt){ //printf("cnt:%d\n",cnt); for(int k=1;k<=n;++k){ for(int i=1;i<=n;++i){ if(!vis[i][k]) continue; for(int j=1;j<=n;++j){ if(!vis[k][j]) continue; vis[i][j]=1; for(int l=0;l<=cnt;++l){ if(dp[l][i][k]>=inf||dp[cnt-l][k][j]>=inf) continue; dp[cnt][i][j]=min(dp[cnt][i][j],dp[l][i][k]+dp[cnt-l][k][j]); } //puts("****"); } } } } for (int i=1; i<=n; i++) { for (int j=1; j<=n; j++) { if (i==j) continue; if (!vis[i][j]) ans[i][j]=-1; else { double res=1e18; for (int k=1; k<=n; k++) { res=min(res,dp[k][i][j]*1.0/k); } ans[i][j]=res; } } } int q=read(); while(q--) { int u=read(),v=read(); if (!vis[u][v]) printf("OMG!\n"); else printf("%.3f\n",ans[u][v]); } }
E-只能吃土豆的牛牛
做法:一定是前i个数进行 2^i -1 次方案数是前 (2^i)-1 小的。于是我们遍历找到第一个大于k的位置
答案加上 这个位置 的前面那个3^(i-1) 然后方案数k 减去2^(i-1) 继续 递归从前往后找 第一个大于k得位置即可。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=(b);++i) #define per(i,a,b) for(int i=a;i>=(b);--i) #define mem(a,x) memset(a,x,sizeof(a)) #define pb push_back #define pi pair<int, int> #define mk make_pair using namespace std; typedef long long ll; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} inline ll read() { ll x=0,w=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();} while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();} return w==1?x:-x; } const int N=33; const ll MAX=1ll<<32; ll f ,ans,val ; void init() { f[0]=1; val[0]=1; for(int i=1;i<N;++i) { f[i]=f[i-1]*2; val[i]=val[i-1]*3; } } ll dfs(int id,ll k) { ll ans=0; if(id<=0||k<=0) return 0; for(int i=0;i<id;++i){ if(f[i]>k){ ans+=val[i-1]; ans+=dfs(i,k-f[i-1]); break; } } return ans; } int main() { init(); int cas=0; int _=read();while(_--) { ll k=read(); ans=dfs(33,k); printf("Case #%d: %lld\n",++cas,ans); } }
相关文章推荐
- 5.25 2020年牛客算法入门课练习赛1
- STL + c++ + 模板 + 重要思维 + 基础算法+ 经典算法 + 经典实例 + 编程总结+ 心得+ 入门必会 + 知识点汇总。+string +dfs +bfs等重要算法
- 【算法竞赛入门经典】6.4.2用BFS求最短路 例题6-14 UVa816
- CodeForces - 786B Legacy(线段树 +最短路+思维好题)
- #2020寒假集训#最短路入门(Floyd弗洛伊德 和 Dijkstra迪杰斯特拉 算法)代码笔记
- [置顶] BFS最短路 4000 径问题新手快速入门
- 牛客网NowCoder 2018年全国多校算法寒假训练营练习比赛(第四场)A.石油采集(dfs) B.道路建设(最小生成树prim) C.求交集(暴力) F.Call to your teacher(迪杰斯特拉乱用) H.老子的全排列呢(dfs)
- World Tour CodeForces - 667D [暴力+bfs求解最短路]
- 【算法系列学习】Dijkstra算法变形 [kuangbin带你飞]专题四 最短路练习
- POJ 2761 据说可以练习线段树主席树划分树splay和treap的一道题。。我用BIT+二分+离散化搞的。。
- 【算法入门】广度/宽度优先搜索(BFS)
- 算法入门学习——暴力递归
- hdu 3333 离线线段树 + 思维/树状数组 /在线主席树
- 算法导论练习4.1-5:求出最大子数组的三种方法:暴力、归并、线性时间算法
- 算法竞赛入门经典第二章练习
- [莫队算法 线段树 斐波那契 暴力] Codeforces 633H Fibonacci-ish II
- 【算法入门】广度/宽度优先搜索(BFS)
- 小白算法练习 PAT Consecutive Factors 暴力|暴力中比较好的题目
- 主席树(可持久化线段树)入门专题
- 【算法入门】广度/宽度优先搜索(BFS)