B乐团派对
题目:https://ac.nowcoder.com/acm/contest/6874/B
题解:贪心的思路,将能力值从小到大排序,先判断能否组成一个乐队,从后开始遍历往前,如果可以得到一个乐队,那么标记此时的位置。否则,输出-1
标记位置后,开始从头遍历到标记的位置,看最多能组成多少队,在标记位置之前的如果组不成一个就融入到最后那个乐队。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=100010; ll n,a[N],i,j; ll maxn=0; ll ans=0; int main() { cin>>n; for(i=0;i<n;i++) cin>>a[i]; sort(a,a+n); ll cnt=0; ll end; for(i=n-1;i>=0;i--) { maxn=max(maxn,a[i]); cnt++; if(cnt==maxn) { ans++; end=i; break; } } if(ans==0) cout<<"-1"<<endl; else { maxn=0; cnt=0; for(i=0;i<end;i++) { maxn=max(maxn,a[i]); cnt++; if(cnt==maxn) { cnt=0; maxn=0; ans++; } } cout<<ans<<endl; } return 0; }
D巅峰对决
题目:https://ac.nowcoder.com/acm/contest/6874/D
题解:一道求最值线段树的问题
代码:
#include<bits/stdc++.h> using namespace std; const int MAXN=1e5+10; typedef long long ll; ll tree[MAXN*4]; ll ans[MAXN*4]; ll n,q; void pushUp(ll p) { tree[p]=tree[p<<1]+tree[p<<1|1]; } void build(ll l,ll r,ll p) { if(l==r) { cin>>tree[p]; ans[p]=tree[p]; return ; } ll mid=(l+r)>>1; build(l,mid,p<<1); build(mid+1,r,p<<1|1); pushUp(p); ans[p]=min(ans[p<<1],ans[p<<1|1]); } //区间求和 ll query(ll l,ll r,ll p,ll i,ll j) { if(j<l||i>r) return 0; if(l>=i&&j>=r) return tree[p]; ll ans=0; ll mid=(l+r)>>1; if(mid>=i) ans+=query(l,mid,p<<1,i,j); if(mid<j) ans+=query(mid+1,r,p<<1|1,i,j); return ans; } //单点更新 void update(ll l,ll r,ll p,ll i,ll j) { if(l==r) { tree[p]=j; ans[p]=j; return; } ll mid=(l+r)>>1; if(mid>=i) update(l,mid,p<<1,i,j); else update(mid+1,r,p<<1|1,i,j); pushUp(p); ans[p]=min(ans[p<<1],ans[p<<1|1]); } //询问区间最值 ll ask(ll l,ll r,ll p,ll a,ll b) { if(b<l||a>r) return 1e18; if(l>=a&&b>=r) return ans[p]; ll v1=0,v2=0; ll mid=(l+r)>>1; v1=ask(l,mid,p<<1,a,b); v2=ask(mid+1,r,p<<1|1,a,b); return min(v1,v2); } int main() { ll op,x,y; cin>>n>>q; build(1,n,1); while(q--) { cin>>op>>x>>y; if(op==1) update(1,n,1,x,y); else { ll minx=ask(1,n,1,x,y); ll sum=query(1,n,1,x,y); ll len=y-x+1; len=len*(minx*2+len-1)/2; if(len==sum) cout<<"YES"<<endl; else cout<<"NO"<<endl; } } return 0; }
E使徒来袭
题目:https://ac.nowcoder.com/acm/contest/6874/E
题解:只要求出战斗力之积的开三次方根的3倍即可
代码:
#include<bits/stdc++.h> using namespace std; int main() { int n; scanf("%d",&n); printf("%.3lf ",3*pow(n,1.0/3)); return 0; }
F核弹剑仙
题目:https://ac.nowcoder.com/acm/contest/6874/F
题解:dfs问题+vector数组解决,先保存每一位比自己武器强的武器编号。
然后从第一个往后逐个深搜,递归搜索每一个比他强的武器编号,并且要标记每一个比他强的武器编号,否则会有重复计算,而且不能使用记忆化数组,会导致重复计算而且标记不全。
代码:
#include<bits/stdc++.h> using namespace std; int n,m,a,b; int v[1010]; vector<int> g[1010]; int dfs(int x) { v[x]=1; int ans=0; for(int i=0;i<g[x].size();i++) { int tmp=g[x][i]; if(!v[tmp]) { ans+=dfs(tmp); v[tmp]=1; ans++; } } return ans; } int main() { int i,j; cin>>n>>m; for(i=0;i<m;i++) { cin>>a>>b; g[b].push_back(a); } for(i=1;i<=n;i++) { memset(v,0,sizeof(v)); cout<<dfs(i)<<endl; } return 0; }
G虚空之力
题目:https://ac.nowcoder.com/acm/contest/6874/G
题解:输入时统计每个字母的个数,优先选择k+2*ing的数字,找出i,n,g三者最小的除以2,再将此数与k比较,如果此数大于k的个数,表示最多有2*k个,否则在判断剩余的k的个数,与剩余的i,n,g三者中较小的个数,再加上这个就为最终的答案。
代码:
#include<bits/stdc++.h> using namespace std; string s; int k,i,n,g,m; int main() { cin>>m; cin>>s; int j=0; for(j=0;j<m;j++) { if(s[j]=='k') k++; else if(s[j]=='i') i++; else if(s[j]=='n') n++; else if(s[j]=='g') g++; } int ans=0; int minx=min(i,min(n,g)); minx=minx/2; if(k>=minx) { ans+=minx*2; i-=minx*2; n-=minx*2; g-=minx*2; k-=minx; int f=min(k,min(i,min(n,g))); ans+=f; } else { ans+=k*2; } cout<<ans; return 0; }
H社团游戏
题目:https://ac.nowcoder.com/acm/contest/6874/H
题解:二维前缀和+二分
首先我们得知道,对于任意一个小写字母,其正方形边长越长,那么在这个矩阵中找到该字母个数和超过k的正方形的可能性也就越大,因此这个边长具有单调性可以二分。
所以我们对每个小写字母预处理一个二维前缀和,然后枚举左上角,之后二分边长。对于每次二分的边长,我们判断其形成的正方形是否符合任意一类小写字母个数之和不超过k就行了。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll n,m,k; char s[510][510]; ll a[26][510][510]; bool check(ll x1,ll y1,ll x2,ll y2) { for(int i=0;i<26;i++) { if(a[i][x2][y2]-a[i][x1-1][y2]-a[i][x2][y1-1]+a[i][x1-1][y1-1]>k) return false; } return true; } int main() { ll i,j,f,l,r,mid; cin>>n>>m>>k; for(i=1;i<=n;i++) { scanf("%s",s[i]+1); } for(f=0;f<26;f++) { for(i=1;i<=n;i++) { for(j=1;j<=m;j++) a[f][i][j]=a[f][i-1][j]+a[f][i][j-1]-a[f][i-1][j-1]+(s[i][j]==f+'a'); } } for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { l=1;r=min(n-i+1,m-j+1); while(l<r) { mid=(l+r)>>1; if(check(i,j,i+mid,j+mid)) l=mid+1; else r=mid; } cout<<l; if(j!=m) cout<<" "; } cout<<endl; } return 0; }
J逃跑路线
题目:https://ac.nowcoder.com/acm/contest/6874/J
题解:首先分析最后横坐标要&上的那堆数,不妨先计算那堆数相&的结果,会发现为1,燃火再看每个a[i]的数据范围,1010000次方,绝对会爆0,因此不能用long long得用striing字符串来存储,由于最后我们需要与1&,我们只需要知道最后一位的相加和即可。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll ans,x; ll n; string s; int main() { cin>>n; for(int i=0;i<n;i++) { cin>>s; int t=s.length(); ans=ans%10+(s[t-1]-'0')%10; } ans=ans&1; cout<<ans; return 0; }