class Solution {
public:
int sumOddLengthSubarrays(vector<int>& a) {
int n = a.size();
int ans = 0;
vector<int> s(n,0);
s[0] = a[0];
for(int i=1;i<n;i++) s[i] = s[i-1]+a[i];
for(int len = 1;len<=n;len+=2){
for(int i=0;i+len<=n;i++){
int ss = s[i+len-1];
if(i) ss -= s[i-1];
ans += ss;
}
}
return ans;
}
};
1589. 所有排列中的最大和
贪心很容易想到,主要是如何统计每个位置的出现的次数。
比赛时想歪了,用了线段树的区间修改懒标记
- 差分维护区间
如果想要给 [ l , r ] [l,r] [l,r]都加上一个增量 d d d,对于差分数组而言其实只有两项发生了变化, s [ l ] = s [ l ] + d ( s [ l ] = a [ l ] − a [ l − 1 ] ) s[l]=s[l]+d(s[l]=a[l]-a[l-1]) s[l]=s[l]+d(s[l]=a[l]−a[l−1]), s [ r + 1 ] = s [ r + 1 ] − d s[r+1]=s[r+1]-d s[r+1]=s[r+1]−d。
所以用差分来维护每次修改的开销是 O ( n ) O(n) O(n)的。
如何还原,差分数组的前缀和就是原数组。
class Solution {
public:
int mod = 1e9+7;
int s[100010] = {
0},a[100010] = {
0};
int maxSumRangeQuery(vector<int>& nums, vector<vector<int>>& requests) {
int n = nums.size();
for(vector<int>& v:requests){
s[v[0]] ++;
s[v[1]+1] --;
}
a[0] = s[0];
for(int i=1;i<n;i++){
a[i] = a[i-1]+s[i];
}
sort(nums.begin(),nums.end());
sort(a,a+n);
long long ans = 0;
for(int i=0;i<n;i++){
ans = (ans+nums[i]*a[i])%mod;
}
return ans;
}
};
- 如果 s u m % p = t a r sum \% p = tar sum%p=tar;
- 那么 被删除的子数组 [l,r] 的和应该在模 p p p意义下等于 t a r tar tar
- s [ r ] ≡ t a r + s [ l − 1 ] ( m o d p s[r] \equiv tar + s[l-1] (\mod p s[r]≡tar+s[l−1](modp
- s [ l − 1 ] ≡ s [ r ] − t a r ( m o d p ) s[l-1] \equiv s[r]-tar (\mod p) s[l−1]≡s[r]−tar(modp)
class Solution {
public:
typedef long long ll;
int minSubarray(vector<int>& nums, int p) {
ll sum = 0;
for(int x:nums) sum += x;
int tar = sum%p;
if(tar==0) return 0;
unordered_map<int,int> mp;
mp[0] = -1;
ll s = 0;
int ans = 1e9, n = nums.size();
for(int i=0;i<n;i++){
s = (s+nums[i])%p;
if(mp.count( ((s-tar)%p+p)%p )){
ans = min(ans,i-mp[ ((s-tar)%p+p)%p ]);
}
mp[s] = i; // 因为求最短
}
if(ans==1e9 || ans==n) return -1;
return ans;
}
};
-
这题拓扑排序的思路很容易想到,然后终点就是实现,也就是要模拟这个拓扑排序的过程了。
-
拓扑排序的过程中最核心的一点就是把入度为0的点入队,然后拓展出更多的点。
如何模拟这个过程?- 首先如何确定一个矩形呢,记录一下某种颜色的左边界、右边界、上边界、下边界,然后在这个矩形里的数字必须是这种颜色或者是通配符(将某个颜色去掉之后,这个点其实就是任意匹配了,将通配符记为0)
- 先把可以去除的矩形入队,然后依次出队,出队后,所在的位置都改成通配符,然后检查是否可以有更多的矩形块产生(相当于就是新的入度为0的点),如果有,入队。
- 反复进行,直至结束。完成标志就是矩阵全都更改为通陪符。
class Solution {
struct Rectangle{
int id;
int x1 = 100,y1 = 100,x2 = 0,y2 = 0;
Rectangle(int id = 0):id(id){
}
void update(int x,int y){
x1 = min(x1,x);
x2 = max(x2,x);
y1 = min(y1,y);
y2 = max(y2,y);
}
}rs[65];
public:
bool vis[65] = {
0};
vector<int> colors;
vector<vector<int>> g;
int m,n;
bool isPrintable(vector<vector<int>>& targetGrid) {
g = targetGrid;
m = g.size();
n = g[0].size();
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(vis[g[i][j]]==0){
vis[ g[i][j] ] = 1;
colors.push_back( g[i][j] );
rs[ g[i][j] ] = Rectangle(g[i][j]);
}
rs[ g[i][j] ].update(i,j);
}
}
memset(vis,0,sizeof(vis));
queue<int> q;
for(int c:colors){
if(check(rs[c]) && !vis[c]){
q.push(c);
vis[c] = 1;
}
}
while(q.size()){
int c = q.front();
q.pop();
updateGrid(rs[c]);
for(int c:colors){
if(!vis[c] && check(rs[c])){
q.push(c);
vis[c] = 1;
}
}
}
return finish();
}
bool finish(){
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
if(g[i][j]) return false;
return true;
}
bool check(const Rectangle& rec){
for(int x=rec.x1;x<=rec.x2;x++)
for(int y=rec.y1;y<=rec.y2;y++)
if(g[x][y]!=rec.id && g[x][y]!=0) return false;
return true;
}
void updateGrid(const Rectangle& rec){
for(int x=rec.x1;x<=rec.x2;x++)
for(int y=rec.y1;y<=rec.y2;y++) g[x][y] = 0;
}
};