牛科小白月赛86
A:比较一下两杯盐水浓度大小即可,第一杯盐水浓度较大就输出S,否则输出Y
void solve() { double a,b,c,d; cin >> a >> b >> c >> d; if(a/b>c/d) cout << 'S' << endl; else cout << 'Y' << endl; }
B:判断一下原有字符串是否出现和答案字符串不一样的选项,如果有,直接0分;否则我都可以帮他选对,10分。不存在5分的情况。
void solve() { string s1,s2; cin >> s1 >> s2; for(int i=0;i<s1.size();i++) { int cnt=0; for(int j=0;j<s2.size();j++) if(s1[i]==s2[j]) cnt=1; if(!cnt) { cout << 0 << endl; return ; } } cout << 10 << endl; }
C:给出某一段连续的定义是:该连续子段的每一个数字都相同
问:m个询问,每次给出一个区间 [l , r] ,问该区间内有多少个连续的子段。
解:我们预处理原数组,将原数组处理为连续递增区间。
例如数组k:
2 2 3 4 5 5 6 2 1 1 1
我们预处理之后k':
1 1 2 3 4 4 5 6 7 7 7
现在如果我要查询区间[2 , 6] 之间又多少个连续子段:那么答案就是 k'[6] - k'[2] = (4 - 1) + 1 ,一共有4个区间
这样,每次都可以O(1)的查询一个区间内有多少连续不同的区间
void solve() { int n,m; cin >> n >> m; vector<int> k(n+10) , vis(n+10); for(int i=1;i<=n;i++) cin >> k[i]; for(int i=1;i<=n;i++) { if(k[i]==k[i-1]) vis[i]=vis[i-1]; else vis[i]=vis[i-1]+1; } while(m--) { int l,r; cin >> l >> r; cout << vis[r]-vis[l]+1 << endl; } }
D:题目就是要我们求有多少个由 ‘ . ’ 组成的长方体。
实现不难,我们可以用dfs或者bfs搜索被裁剪下来的连通块。
对于每一个连通块,我们记录该连通块的大小,以及左上的(x , y)坐标以及右下的(x , y)坐标。
知道一个长方体的左上角和右下角坐标之后,我们就可以用长方体的体积和连通块的大小进行比较,如果长方体体积正好等于连通块大小,ans++。
// /l、 //(゚、 。 7 // l、 ~ヽ // じしf_, )ノ // 不要放弃!猫猫会为你加油! #include <bits/stdc++.h> #define endl '\n' #define int long long using namespace std; const int N = 2e5+10 , M = 1e6+10 , INF = 1e9+7; int n,m; int cnt=0,w=0,x_,y_,x2,y2; int g[1010][1010]; struct node { int xx,yy,xt,yt; }k[1000010]; void dfs(int x,int y) { x_=min(x_,x) , x2=max(x2,x); y_=min(y_,y) , y2=max(y2,y); w++; g[x][y]=cnt; if(x-1>=1 && g[x-1][y]==0) dfs(x-1,y); if(x+1<=n && g[x+1][y]==0) dfs(x+1,y); if(y-1>=1 && g[x][y-1]==0) dfs(x,y-1); if(y+1<=m && g[x][y+1]==0) dfs(x,y+1); } void solve() { cin >> n >> m; map<int , int> mp; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { char t; cin >> t; if(t=='*') g[i][j]=-1; else g[i][j]=0; } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(g[i][j]==0) { cnt++ , w=0; x_=INF , y_=INF , x2=0 , y2=0; dfs(i,j); mp[cnt]=w; k[cnt]={x_,y_,x2,y2}; } } } int ans=0; for(int i=1;i<=cnt;i++) { if((k[i].xt-k[i].xx+1)*(k[i].yt-k[i].yy+1) == mp[i]) ans++; } cout << ans << endl; } signed main() { ios::sync_with_stdio(0); cin.tie(0) , cout.tie(0); int T = 1; // cin >> T ; while(T--) solve(); return 0; }
E:我们知道要在满足饱食度W的情况下,使得可口值最大。
n*n暴力肯定是不行的,会狠狠滴TLE!
那么我们要怎么办呢,题目要求吃的是一段连续的食物使得饱食度达到W对吧!
那说明什么?说明饱食度是递增的!所以我们可以用二分来解决这个问题。
我们首先求一个关于w的前缀和数组。然后我们去枚举以当前点为吃东西的起点,寻找最优的满足饱食度大于等于W的情况下的最大可口度。
首先枚举起点,然后二分出饱食度大于等于W的另一个右端点。自这个右端点往后,都是满足饱食度大于等于W的。
那么还有一个问题,我们怎么保证,可口度最大呢?我们可以将可口值先求一个前缀和数组,然后求一个可口度的后缀最大值!
这样,对于每一个点,我们都知道以他为起点的可以达到的最大可口度。
那么答案就出来了,用二分出的右端点后面的最大可口度减去当前起点之前的可口度,答案在取个min就行。
void solve() { int n,m; cin >> n >> m; vector<int> k(n+10) , d(n+10) , visk(n+10) , visd(n+10) , suf(n+10); for(int i=1;i<=n;i++) cin >> k[i] , visk[i]=visk[i-1]+k[i]; for(int i=1;i<=n;i++) cin >> d[i] , visd[i]=visd[i-1]+d[i]; suf[n]=visd[n]; for(int i=n-1;i>=1;i--) suf[i]=max(suf[i+1],visd[i]); int ans=-INF; for(int i=1;i<=n;i++) { int l=i , r=n; while(l<=r) { int mid = l+r >> 1; if(visk[mid]-visk[i-1]>=m) r=mid-1; else l=mid+1; } if(l==n+1) break; ans=max(ans,suf[l]-visd[i-1]); } cout << ans << endl; }