- 板刷!!! !
二分模板
//查找左边界 SearchLeft 简写SL
int SL(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;
}
//查找右边界 SearchRight 简写SR
int SR(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1; //需要+1 防止死循环
if (check(mid)) l = mid;
else r = mid - 1;
}
return r;
}
前缀和模板
一维前缀和 :
s[i] = s[i - 1] + a[i];
二维前缀和
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1])
acwing 796. 子矩阵的和
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n, m, q;
const int N = 1010;
int s[N][N], a[N][N];
int main () {
cin >> n >> m >> q;
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
cin >> a[i][j];
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
}
}
while (q -- ) {
int x1, x2, y1, y2;
cin >> x1 >> y1 >> x2 >> y2;
cout << s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] << endl;
}
return 0;
}
前缀和模板题
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N], s[N];
int n, m, l, r;
int main (){
cin >> n >> m;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
}
for(int i = 1; i <= n; i ++) {
s[i] = s[i - 1] + a[i];
}
while(m -- ) {
cin >> l >> r;
cout << s[r] - s[l - 1] << endl;
}
return 0;
}
四平方和 (哈希)
思路 : 哈希存储 cd集合 然后枚举
a
和b
时间复杂度O(n 2)
#include <bits/stdc++.h>
// #include <iostream>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back;
#define fs first;
#define sz second;
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n";
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
const int N = 5000010;
int n;
int C[N], D[N];
void solve() {
cin >> n;
memset(C, -1, sizeof C);
for(int c = 0; c * c <= n; c ++) {
for(int d = c; d * d + c * c <= n; d ++) {
int s = c * c + d * d; // 哈希存储所有和的 集合
if(C[s] == -1) {
C[s] = c, D[s] = d;
}
}
}
for(int a = 0; a * a <= n; a ++) {
for(int b = a; b * b + a * a <= n; b ++) {
int t = n - a * a - b * b;
if(C[t] != -1) {
// 如果和在集合中
cout << a << ' ' << b << " " << C[t] << ' ' << D[t] << endl;
return ;
}
}
}
}
// void solve () {
// }
int main(void){
// freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T = 1;
// cin >> T;
while(T --) solve();
return 0;
}
分巧克力 ( 二分 )
思路 : 二分 ! 条件 : 每块巧克力可以分的个数 之和 与人数做对比
#include <bits/stdc++.h>
// #include <iostream>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back;
#define fs first;
#define sz second;
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n";
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
const int N = 1e5 + 10;
int n, m;
int h[N], w[N];
bool check (int mid) {
//判断条件 : 拆剪巧克力个数 大于人数 则返回true
// 否则 返回 false
ll res = 0;
for(int i = 0; i < n; i ++) {
res += (ll)h[i] / mid *(ll) (w[i] / mid);
if(res >= m) return true;
// 乘积的下取整 与 下取整后乘积 结果不同!!
// 需要 下取整后 再 乘积
}
return false;
}
void solve () {
cin >> n >> m;
for(int i = 0; i < n ; i ++) {
cin >> h[i] >> w[i];
}
int l = 1, r = 1e5 + 10;
//因为是最大值 所以查找左边界
while (l < r) {
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout << r << endl;
}
int main(void){
// freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T = 1;
// cin >> T;
while(T --) solve();
return 0;
}
K倍区间 (前缀和)
思路 :
结论:%k,余数相同的相减 = k的倍数 – >
数学思路 统计余数相同的前缀和,如果在这些前缀和中余数相同的任取俩个相减,他们得到的余数都是相同的。
#include <bits/stdc++.h>
// #include <iostream>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back;
#define fs first;
#define sz second;
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n";
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
const int N = 1e5 + 10;
int n, k;
ll a[N], cnt[N];
void solve () {
cin >> n >> k;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
a[i] += a[i - 1];
}
ll res = 0;
cnt[0] = 1;
rep(i, 1, n) {
res += cnt[a[i] % k];
cnt[a[i] % k] ++;
}
cout << res << endl;
return;
}
int main(void){
freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T = 1;
// cin >> T;
while(T --) solve();
return 0;
}
激光炸弹
思路 :
#include <iostream>
using namespace std;
const int N = 5010;
int s[N][N];//c++ 大数组开全局
int main () {
int N,R;// C++重名优先使用局部变量
cin >> N >> R;
R = min (R, 5001);
int n = R,m = R;
for (int i = 0,x,y,w; i < N; i ++) {
cin >> x >> y >> w;
s[x+1][y+1] += w;
//映射到1 ,为了满足题意不考虑边界
n = max(n, x+1),m= max(m, y+1);//更新最大边界
}
for(int i = 1;i <= n;i ++) {
for(int j = 1;j <= m; j ++) {
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + s[i][j];
}
}
int ans = 0;
for (int i = R; i <= n; i ++) {
for (int j = R; j <= m; j ++) {
ans = max (ans,s[i][j] - s[i - R][j] - s[i][j - R] + s[i -R][j - R]);
}
}
cout << ans << endl;
return 0;
}
3956. 截断数组
思路 :
只需要枚举俩刀即可, 中间部分不用管的 , 只管 左边和右边部分的值是否等于s[n] / 3
如果是,则加上cnt ++
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> PII;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n"
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
const int N = 100010;
const int M = N * 2;
#define x first
#define y second
int s[N];
void solve () {
int n;
ll ans = 0;
cin >> n;
for(int i = 1; i <= n; i ++) {
cin >> s[i];
s[i] += s[i - 1];
}
int t = s[n] / 3;
if(s[n] % 3 == 0) {
// 因为要把数组均分三份,总和一定得是3的倍数
for(int i = 1; i < n - 1; i ++) {
cnt = 0;
if(s[i] == t) cnt ++;
if(s[n] - s[i + 1] == t) ans += cnt;
}
}
cout << ans << endl;
}
int main(void){
// freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T = 1;
// cin >> T;
while(T --) solve();
return 0;
}
机器人跳跃
- 题解 (二分 & 递推)https://www.acwing.com/solution/content/90581/
- ceil(e) 函数 - 》 向上取整!!
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 100010;
int h[N];
int main ( ) {
int n;
cin >> n;
for (int i =1; i <= n; i ++ ) {
cin >> h[i];
}
double e = 0;
for(int i = n - 1; i >= 0; i --) {
// 最多到 n 座建筑 又 h[i + 1] 所以从 n -1 开始
e = (e + h[i + 1]) / 2;
}
cout << ceil(e) << endl;
return 0;
}
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 100010;
int n;
int h[N];
bool check(int x) {
for (int i =1; i <= n; i ++ ) {
x = 2 * x - h[i];
if(x < 0) return false;
if(x > 1e5) return true; // 加速退出 不然会TLE
}
return true;
}
int main ( ) {
cin >> n;
for (int i =1; i <= n; i ++ ) {
cin >> h[i];
}
int l = 1, r = 1e5; // 最大范围为题目数据范围
while(l < r) {
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
return 0;
}
1
思路 :