思路:
三个for判断一下就好了。
但是判断等比数列的时候不能直接除,因为不一定全部整除。
a[2] / a[1] = a[i] / a[i - 1]
a[2] * a[i - 1] = a[i] * a[1]
变成乘法就行了。
#include<iostream> #include<queue> #include<string> #include<cstring> #include<algorithm> using namespace std; long long int a[200000]; void solved(){ int n;cin >> n; for(int i = 1; i <= n; i++)cin >> a[i]; bool f1 = true; for(int i = 2; i <= n; i++){ if((a[2] - a[1]) != (a[i] - a[i - 1])){ f1 = false;break; } } bool f3 = true; for(int i = 2; i <= n; i++){ if((a[2] % a[1]) != (a[i] % a[i - 1])){ f3 = false;break; } } bool f2 = true; for(int i = 2; i <= n; i++){ if(a[2] * a[i - 1] != a[i] * a[1]){ f2 = false;break; } } if(f1 || f2 || f3)cout << "YES" << endl; else cout << "NO" << endl; } int main(){ solved(); return 0; }
思路:
呜呜呜,这题一开始没看懂跳过去了,最后回过来来看终于看懂了,可惜也没时间了。
每找到一个NowCoder就可以开始计算贡献,会等于它左边的数量乘上右边的数量。
不过一个字符串如果出现两次NowCoder不满足条件,所以我们需要记录一下上一次NowCoder出现的位置。
然后计算贡献即可。
#include<iostream> #include<queue> #include<string> #include<cstring> #include<algorithm> using namespace std; const int maxn = 2e5 + 10; char s[maxn]; void solved(){ scanf("%s",s + 1); int len = strlen(s + 1); long long int ans = 0; int last = 0; for(int i = 1; i <= len; i++){ if(i + 7 <= len && s[i] == 'N' && s[i + 1] == 'o' && s[i + 2] == 'w' && s[i + 3] == 'C' && s[i + 4] == 'o' && s[i + 5] == 'd' && s[i + 6] == 'e' && s[i + 7] == 'r'){ ans += (i - last) * (len - (i + 7) + 1); last = i; } } cout << ans << endl; } int main(){ solved(); return 0; }
思路:
这个题应该是全场最简单的题吧。。。。但是有点细节。。。。而且旋转45度我还是不太熟导致还是没过去,但是思路还是秒了。
因为它是一个菱形,所以我们可以先将这个菱形旋转45度,然后做一个二维前缀和求最大值就行了。
em。。。这题主要就是旋转不太好搞,其它的都还行。
旋转的话,
拿这个旋转为例,可以发现旋转后的菱形是一个n * n + 1,n * n + 1这样的,然后我们可以根据左右对角线我们可以发现原来第(i,j)位置的数字存在旋转后的第(n+i-j,i+(j-1))这个位置。并且我们需要把这个位置标记一下,便于我们枚举所有点的时候确保枚举的点是实实在在存在的点。然后做一个二维前缀和,然后枚举所有点求最大值就好了。
害,,,这种旋转45度的题已经是我第二次做了,我还是没写出来,呜呜呜。。。
代码:
#include<iostream> #include<queue> #include<string> #include<cstring> #include<algorithm> using namespace std; typedef long long int ll; const int maxn = 5e3 + 10; int num[maxn][maxn]; ll sum[maxn][maxn]; bool vis[maxn][maxn]; void solved(){ int n,k;cin >> n >> k;k--; for(int i = 1; i <= n + n - 1; i++) for(int j = 1; j <= n + n - 1; j++) num[i][j] = sum[i][j] = 0 ; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%d", &num[n+i-j][i+(j-1)]),vis[n+i-j][i+(j-1)] = 1 ; for(int i = 1; i <= n + n - 1; i++) for(int j = 1; j <= n + n - 1; j++) sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + num[i][j]; ll ans = 0; for(int x = 1; x <= n + n; x ++){ for(int y = 1; y <= n + n; y++){ if(!vis[x][y])continue; int r2 = min(n + n - 1, x + k), r1 = max(1, x - k) ; int c2 = min(n + n - 1, y + k), c1 = max(1, y - k) ; ans = max(ans,sum[r2][c2]-sum[r2][c1-1]-sum[r1-1][c2]+sum[r1-1][c1-1]); } } cout << ans << endl; } int main(){ solved(); return 0; }
思路:
这题写的二分把孩子t傻了,原来正解是并查集(好像也不是很难,为啥孩子要写二分)
为了找到最大的L并且是通路,我们可以把所有路的权值从大到小排序,然后一个一个加到并查集中,一旦s到t是联通的(即父亲节点相同)此时的权值就是最大的L。
当然最大L的路径非常多,我们还需要找最小的R,那么相同的做法,对所有权从小到大排序,然后权小于L的不用考虑,然后一个一个加到并查集中去,一旦s到t联通此时的权就是最小的R。
代码:
#include<iostream> #include<queue> #include<string> #include<cstring> #include<algorithm> using namespace std; const int maxn = 6e6 + 10; struct edge{ int u,v,w; }e[maxn]; bool cmp(edge a,edge b){ return a.w > b.w; } bool cmp2(edge a,edge b){ return a.w < b.w; } int f[maxn]; int find(int x){ if(x != f[x]){ return f[x] = find(f[x]); } return f[x]; } void solved(){ int n,m,s,t; scanf("%d%d%d%d",&n,&m,&s,&t); int tot = 0; for(int i = 1; i <= m; i++){ int a,b,c;scanf("%d%d%d",&a,&b,&c); e[++tot] = {a,b,c}; } sort(e + 1,e + 1 + tot,cmp); int L,R; for(int i = 1; i <= n; i++)f[i] = i; for(int i = 1; i <= tot; i++){ int fu = find(e[i].u); int fv = find(e[i].v); if(fu != fv)f[fu] = fv; if(find(s) == find(t)){ L = e[i].w; break; } } for(int i = 1; i <= n; i++)f[i] = i; sort(e + 1,e + 1 + tot,cmp2); for(int i = 1; i <= tot; i++){ if(e[i].w < L)continue; int fu = find(e[i].u); int fv = find(e[i].v); if(fu != fv)f[fu] = fv; if(find(s) == find(t)){ R = e[i].w;break; } } printf("%d %d\n",L,R); } int main(){ solved(); return 0; }