就把可以凑对的凑在一起,不能的俩俩组合
题目思路:
算出全放糖果的sum,算出与留下糖果的差cha
可知,每少放一次就会减少N-i个糖果,i >= 1(因为不放还吃了)
cha就是少了的糖果的总和,根据等差数列求和公式
进行二分查找少放了几次,就是吃了几次
题目代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> N >> M; LL sum =(N*(1+N))/2; LL s = sum - M; LL l = 0; LL r = N; LL mid; while(l <= r) { mid = (l+r)/2; LL cha = s - mid; LL su = (mid*(N+N-mid+1))/2; if(cha > su) { l = mid+1; } else if(su > cha) { r = mid-1; } else break; } cout << mid << endl; return 0; }
|
题目思路:
感觉瞎写就过了,我也不知道是贪心还是dp
就保证每走一步从上下出来的时候sum是最大的,每一步有俩中走法,一种是从下面上来,一种是刚才空了一个上面没走
题目代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| LL a[MAX]; LL b[MAX]; LL sum[2][MAX];
int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> N; for(int i = 0;i < N;i++) { cin >> a[i]; } for(int i = 0;i < N;i++) { cin >> b[i]; } LL s[2]; s[0] = a[0]; s[1] = b[0]; for(int i = 1;i < N;i++) { LL u,d; u = s[0]; d = s[1]; s[0] = max(d+a[i],u - a[i-1]+a[i]); s[1] = max(u+b[i],d - b[i-1]+b[i]); } cout << max(s[0],s[1]); return 0; }
|
题目思路:
以123 45 6为例子可以组成
112233 12435 1236
14253 4455 456
1236 66 465
首先定义一个数组ten={0,1,10,···}
每一个数字都表示为第k(自右)位的值*ten[k]
经过观察可以发现,每个数字对答案的贡献次数为2*N
还可以发现,每位上的数字贡献是相同的(*ten[i]和次数是相同的)
(看123的2,和45的4,分别2 * 1000 * 2 + 2 * 100 * 4,4 * 1000 * 2 + 4 * 100 * 4)
所以我们把每一位上的数字加起来存到sum[i]
我们还需要一个数组记录长度为k的数字有多少个len[i]
然后我们把情况分为俩种
对于第k位的贡献,可以分为俩类
1.长度>=k的数字n,为sum[k] * (ten[2 * k] + ten[2 * k - 1]) * len[i](i为n的长度)
2.长度<k的数字n,为sum[k] * ten[k + i] * 2 * len[i]
题目代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| LL ten[MAX]; LL len[MAX]; LL sum[MAX];
int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> N; string str; LL ans = 0; ten[1] = 1; for(int i = 2;i <= 24;i++) { ten[i] = (ten[i-1]*10) % MOD; } int maxl = 0; for(int i = 0;i < N;i++) { cin >>str; int l = str.size(); maxl = max(maxl,l); len[l]++; for(int i = l-1,j = 1;i >=0;i--,j++) { sum[j] += (LL)(str[i] - '0'); } } for(int i = maxl;i > 0 ;i--) { for(int j = maxl;j > 0;j--) { if(j < i) ans += ((sum[i] * ten[j+i]) % MOD) * len[j] * 2 % MOD; else if(j == i || j > i) { ans += ((sum[i] * ten[2*i]) % MOD) * len[j] % MOD; ans += ((sum[i] * ten[2*i-1]) % MOD) * len[j] %MOD; } } } cout << ans % MOD<<endl; return 0; }
|
这是一个在O(N)复杂度内在一个区间内找到子区间最小值的方法
实现单调队列的方法:
1.滑动窗口右滑。每年选拔新队员时,淘汰比这名新队员弱的老队员。对于单调队列,就是插入新元素时,把先前存在的比当前元素小的元素弹出(从队尾退队)。
2.滑动窗口右滑。只需判断最老的队员是否需要退队。对于单调队列,只需判断队头是否已经超出滑动窗口范围,若超出,则从队头退队。
3.查询滑动窗口最大值。直接派最老的队员参赛/直接返回队头元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| struct Num{ int index,x; };
int a[MAXN]; deque<Num> q;
int main(void){ int n,m; Num t; scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<=n;i++){ if (q.empty()) printf("0\n"); else { if (q.front().index+m<i) q.pop_front(); printf("%d\n",q.front().x); } while ((!q.empty()) && q.back().x>=a[i]) q.pop_back(); t.index=i; t.x=a[i]; q.push_back(t); } return 0; }
|
题目思路:
题意是给你一个矩阵h(N * M),然后问你h中所有子矩阵(a * b)中的最小值的sum
首先第一步找到矩阵hij,我们可以根据题意推论出$g_0 - g_{m-1}$就是矩阵第一行,第二行从gm开始
然后我们把1-N行每一行中的区间(0,b-1)(1,b)···(M-b+1,M)的最小值找到,得到矩阵hgt
然后我们再把矩阵hgt中每一列区间(0,a-1) (1.a) ··· (N-a+1,N)的最小值找到,这里最小值就是每一个子矩阵的最小值了
找最小值就通过单调队列来找
题目代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| int hgt[MAX][MAX];
int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int a,b; cin >> N >> M >> a >> b; LL g,x,y,z; cin >> g >>x>>y>>z; int k; for(int i = 1;i <= N;i++) { deque<pair<int,int>> q; k = 1; for(int j = 1;j <= M;++j) { while(q.size() && q.back().first >= g) q.pop_back(); while(q.size() && q.front().second < j-b+1) q.pop_front(); q.push_back({g,j}); if(j >= b) { hgt[i][k++] = q.front().first; } g = (g*x + y) % z; } } LL ans = 0; for(int j = 1;j <= M;j++) { deque<pair<int,int>> q; for(int i = 1;i <= N;++i) { while(q.size() && q.back().first >= hgt[i][j]) q.pop_back(); while(q.size() && q.front().second < i - a+1) q.pop_front(); q.push_back({hgt[i][j],i}); if(i >= a) { ans += (LL)q.front().first; } } } cout << ans; return 0; }
|