本篇解题记录题源来自 AcWing 的 Summer 每日一题

补题链接:Here

2021/07/01 done

Week 1

星期一 AcWing 3485. 最大异或和 (Hard

思路

先求出前i个数的异或和sum[i],再在大小为m的滑动窗口内进行trie.

  • \(\mathcal{O}(nlog\ n)\)
int n, m;
const int N = 31e5 + 10; //最多有n*31
int p[N][35], ct[N], idx; //ct[n]的作用是标记滑动窗口内0,1的数量 int sum[100010]; //sum[i]存前i个数的异或和
void insertt(int u, int c) {
int t = 0;
for (int i = 30; i >= 0; i--) {
int x = u >> i & 1;
if (!p[t][x]) {
p[t][x] = ++idx;
}
t = p[t][x];
ct[t] += c; //标记这里(有或删除)一个数可以达到该位置
}
}
int query(int u) {
int t = 0;
int res = u;
for (int i = 30; i >= 0; i--) {
int x = u >> i & 1;
if (ct[p[t][!x]] > 0) { //当x对面的那个数!x存在时(0,1)
x = (x + 1) % 2; //x就变成另外一个数 !x
}
res ^= x << i;
t = p[t][x];
}
return res;
}
void solve() {
cin >> n >> m;
int t;
for (int i = 1; i <= n; i++) {
cin >> t;
sum[i] = sum[i - 1] ^ t; //sum[i]表示前i个数的^
}
insertt(0, 1); //插入0,是为了方便前m个数进行异或得出的答案可以是它本身的值
int res = 0; //求最大值
for (int i = 1; i <= n; i++) {
if (i > m) insertt(sum[i - m - 1], -1); //将滑动窗口外的数除去,这时就要修改ct,故-1
res = max(res, query(sum[i])); //在滑动窗口内求最大值
insertt(sum[i], 1); //求完后记得插入该值,方便后面的值进行异或
}
cout << res;
}

星期二 AcWing 3493. 最大的和 (Easy

对于 \(30\%\) 数据,可以开两重 for 循环暴力找

但在 \(100\%\) 数据里肯定会 T

所以要用前缀和进行优化 (当然也可以用队列优化,这里就不展开了,贴一个讲解链接

  • \(\mathcal{O}(n)\)
using ll    = long long;
const int N = 1e5 + 10;
ll a[N], s[N];
ll st[N];
void solve() {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; ++i) cin >> a[i];
ll sum = 0;
for (int i = 1; i <= n; ++i) {
cin >> st[i];
if (st[i]) s[i] += s[i - 1], sum += a[i]; // 如果是 st[i] = 1 的情况说明直接就可选,sum 累加即可
else
s[i] = s[i - 1] + a[i]; // 需要转换状态的话则要利用前缀和累加了
}
ll res = 0;
for (int i = k; i <= n; ++i) res = max(res, s[i] - s[i - k]);
cout << res + sum;
}

星期三 AcWing 3499. 序列最大收益 (Mid

参考最长上升子序列

  • f[i][j] 表示从0~i-1 中删j个点后,0~i 的收益最大值

    • 或者说成前i个点中删j个数,保留i的最大收益
  • 按i来划分集合,可以划分为0~i-1,其中0就代表前0个点删j个数,等价于不删.
  • f[i][j]可以从f[u][?]转移过来,我们对f[i][j]做一个转换
    • 既然要删j个数,可以先把后面[u+1,i-1]给删了,这样会删除i-1-u个数
    • 然后再在前面[0,u]中删j-(i-1-u)个数,此时u点和i点临近,可加贡献 w[a[u]][a[j]]

      故可以得到如下状态转移方程 f[i][j] = max(f[i][j],f[u][j-(i-u-1)]+w[a[u]][a[i]]);
const int N = 210;
int n, k, m;
int a[N]; // 记录元素
int w[N][N]; // w[i][j]表示i->j的收益
int f[N][N]; // f[i][j] 表示0~i-1中删除j个点后,0~i的最大收益
void solve() {
cin >> n >> k >> m;
for (int i = 1; i <= m; ++i) cin >> a[i];
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
cin >> w[i][j];
memset (f, -0x3f, sizeof (f) );
f[1][0] = 0; // init
// 第1个点删0个数保留1的收益为0
for (int i = 1; i <= m; i ++ )
for (int j = 0; j <= k; j ++ ) //j从0~k,不删就是0
for (int u = 1; u < i; ++ u) //最多删i-1个
if (j >= i - u - 1) //注意是>=,=的条件下就说明既可以把后面删完,也可以直接分配到0~i中
//故要计算状态
f[i][j] = max (f[i][j], f[u][j - (i - u - 1)] + w[a[u]][a[i]]);
int ans = 0;
for (int i = 0; i <= k; ++i) ans = max (ans, f[m][i]);
cout << ans << '\n';
}

星期四 AcWing 3502. 不同路径数

这道题,爆搜 + set去重即可

const int N = 10;
int n, m, k;
int e[N][N];
set<int>S;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
int res = 0;
void dfs(int sx, int sy, int u, int s) {
if (u == k) {
if (!S.count(s)) ++res, S.insert(s);
return;
}
for (int i = 0; i < 4; ++i) {
int x = sx + dx[i];
int y = sy + dy[i];
if (x < 1 || x > n || y < 1 || y > m)continue;
dfs(x, y, u + 1, s * 10 + e[x][y]);
}
}
void solve() {
cin >> n >> m >> k;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
cin >> e[i][j];
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
dfs(i, j, 0, e[i][j]);
}
cout << res;
}

星期五 AcWing 3510. 最长公共子序列 (Mid

const int N = 1e6 + 7;
int id[N], q[N];
void solve() {
int n;
cin >> n;
memset(id, -1, sizeof(id));
for (int i = 0, x; i < n; ++i) {
cin >> x;
id[x] = i;
}
int tt = 0;
q[0] = -1;
for (int i = 0, x; i < n; ++i) {
cin >> x;
int k = id[x];
if (k == -1)continue;
int l = 0, r = tt;
while (l < r) {
int mid = l + (r + 1) >> 1;
if (q[mid] < k)l = mid;
else r = mid - 1;
}
q[r + 1] = k;
tt = max(tt, r + 1);
}
cout << tt << '\n';
}

星期六 AcWing 3489. 星期几 (Easy)

套公式,或者逐年累加

int Day(int y, int m, int d) {
if (m == 1 || m == 2) m += 12, y -= 1;
return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400 +
1) % 7;
}
string D[] = {
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
};
string DD[] = {
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
}; void solve() {
int y, d, mm;
string m;
while ( cin >> d >> m >> y) {
for (int i = 0; i < 12; ++i)
if (m == D[i])cout << DD[(Day(y, i + 1, d))] << "\n";
}
}

星期日 AcWing 3481. 阶乘的和

using ll = long long;
int fact[20];//10!就大于1e6
int combin[4100];//存所有阶乘能组合出来的数,0~10有11种阶乘,2^11空间存储
int m = 0;
void dfs(int u, int st) {
if (u == 11) {
int res = 0;
for (int i = 0; i < 11; ++i) {
if (st >> i & 1) {
res += fact[i];
}
}
combin[m++] = res;
return;
}
dfs(u + 1, st);
dfs(u + 1, st | 1 << u);
}
void solve() {
fact[0] = 1;
for (int i = 1; i <= 10; ++i) fact[i] = fact[i - 1] * i;
dfs(0, 0);
sort(combin, combin + m);
// m = unique(combin, combin + m) - combin; // 去重,可有可无
int x;
while (cin >> x, x >= 0) {
int l = 1, r = m - 1;
int mid = l + r >> 1;
//二分查找预处理数组
while (l < r) {
mid = l + r >> 1;
if (combin[mid] >= x) r = mid;
else l = mid + 1;
}
cout << (combin[l] != x ? "NO\n" : "YES\n");
}
}

Week 2

星期一 AcWing 3516. 最大面积 (Hard

第一眼看过去像二维前缀和问题,但实际要使用单调栈解决

下面给出 4 道相关知识点递增的题目

830.单调栈 -> 131. 直方图中最大的矩形 -> 152. 城市游戏 -> 3516. 最大面积


Y总视频讲解,建议直接空降 30 min

const int N = 2010;
char g[N][N];
int l[N], r[N], q[N];
int U[N], D[N], L[N], R[N];
int s[N][N];
int n, m; int calc(int h[], int n) {
h[0] = h[n + 1] = -1;
int tt = 0;
q[0] = 0;
for (int i = 1; i <= n; i ++ ) {
while (h[q[tt]] >= h[i]) tt -- ;
l[i] = q[tt];
q[ ++ tt] = i;
}
tt = 0;
q[0] = n + 1;
for (int i = n; i; i -- ) {
while (h[q[tt]] >= h[i]) tt -- ;
r[i] = q[tt];
q[ ++ tt] = i;
}
int res = 0;
for (int i = 1; i <= n; i ++ )
res = max(res, h[i] * (r[i] - l[i] - 1));
return res;
}
void init() { // 注意初始化别写错...
for (int i = 1; i <= n; ++i) { // 枚举行
for (int j = 1; j <= m; ++j)
if (g[i][j] == '1')s[i][j] = s[i - 1][j] + 1;
else s[i][j] = 0;
U[i] = max(U[i - 1], calc(s[i], m));
}
memset(s, 0, sizeof(s));
for (int i = n; i; i--) { // 枚举行
for (int j = 1; j <= m; ++j)
if (g[i][j] == '1')s[i][j] = s[i + 1][j] + 1;
else s[i][j] = 0;
D[i] = max(D[i + 1], calc(s[i], m));
}
memset(s, 0, sizeof(s));
for (int i = 1; i <= m; i ++ ) { // 枚举列
for (int j = 1; j <= n; j ++ )
if (g[j][i] == '1') s[i][j] = s[i - 1][j] + 1;
else s[i][j] = 0;
L[i] = max(L[i - 1], calc(s[i], n));
}
memset(s, 0, sizeof(s));
for (int i = m; i; i -- ) { // 枚举列
for (int j = 1; j <= n; j ++ )
if (g[j][i] == '1') s[i][j] = s[i + 1][j] + 1;
else s[i][j] = 0;
R[i] = max(R[i + 1], calc(s[i], n));
}
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; ++i)scanf("%s", g[i] + 1);
init();
int _;
cin >> _;
while (_--) {
int x, y;
cin >> x >> y, x++, y++;
cout << max(max(U[x - 1], D[x + 1]), max(L[y - 1], R[y + 1])) << "\n";
}
}

星期二 AcWing 3404. 谁是你的潜在朋友

按题意来,把看同一本书的人放进数组。

意外的简单

void solve() {
int n, m;
cin >> n >> m;
bool vis[n + 1] = {false};
int b[n + 1];
vector<int>a[m + 1];
for (int i = 1; i <= n; ++i) {
cin >> b[i];
a[b[i]].push_back(i);
}
for (int i = 1; i <= n; ++i) {
if (a[b[i]].size() == 1)cout << "BeiJu\n";
else cout << a[b[i]].size() - 1 << "\n";
}
}

星期三 AcWing 3483. 2的幂次方

这道题,本质是对在二进制下的1进行递归处理

int n;
string dfs(int n) {
string str;
for (int i = 20; i >= 0; --i) {
int f = 1 << i;
if (i > 2 and (n & f)) {
str += "2(";
str += dfs(i);
str += ')';
n -= f;
if (n != 0) str += '+';
} else if (i <= 2 and (n & f)) {
if (i == 0)str += "2(0)";
if (i == 1) str += "2";
if (i == 2) str += "2(2)";
n -= f;
if (n != 0) str += '+';
}
}
return str;
}
void solve() { while (cin >> n)cout << dfs(n) << "\n";}
// 简化代码
string dfs(int x) {
if (!x)return "0";
string ans = "";
for (int j = 31; j >= 0; --j) {
if ((x >> j) & 1) ans += (j == 1) ? "2+" : "2(" + dfs(j) + ")+";
}
return ans.substr(0, ans.size() - 1);
}
void solve() {
int n;
while (cin >> n)cout << dfs(n) << "\n";
}

星期五 AcWing 3333. K-优字符串

int Case = 1;
void solve() {
int n, k, sum = 0;
cin >> n >> k;
string s;
cin >> s;
int l = 0, r = s.size() - 1;
while (l < r) {
if (s[l] != s[r])sum++;
l++, r--;
}
cout << "Case #" << Case++ << ": " << abs(sum - k) << "\n";
}

Week 3

星期一 AcWing 3554. 二进制

解法一: 模拟,二进制累加,当存在溢出时,即最后 c = 1 时要多输出一个 1

void solve() {
string a, b;
cin >> a, b = a;
int c = 0;
for (int i = 31; i >= 0; i -= 1) {
int tmp = (a[i] - '0') + c;
if (i == 31)tmp++;
a[i] = (tmp % 2) + '0';
c = tmp / 2;
}
if (c) cout << c;
cout << a << "\n";
c = 0;
for (int i = 31; i >= 0; i -= 1) {
int tmp = (b[i] - '0') + c;
if (i == 31 || i == 30)tmp++;
b[i] = (tmp % 2) + '0';
c = tmp / 2;
}
if (c)cout << c;
cout << b << "\n";
}

解法二:转换成 long long 计算

using ll = long long;
void f(ll n) {
if (n >> 32 & 1)cout << 1;//最大的32位加3会变成33位,检查一下
for (int i = 31; i >= 0; i -= 1) {
if (n >> i & 1)cout << 1;
else cout << 0;
}
cout << "\n";
}
void solve() {
string s; cin >> s;
ll n = 0;
for (int i = 0; i < 32; ++i)
if (s[i] == '1')
n = n | (1ll << (31 - i));
f(n + 1), f(n + 3);
}

解法三:Python 不讲武德

T = int(input())for _ in range(T):
n = int(input(),2)
print(bin(n+1)[2:].rjust(32, '0'))
print(bin(n+3)[2:].rjust(32, '0'))

星期二 AcWing 3565. 完美矩阵

using ll = long long;
const int N = 110;
ll a[N][N];
vector<int>e[N][N];
void solve() {
int n, m; cin >> n >> m;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)e[i][j].clear();
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
cin >> a[i][j];
e[min(i, n - i + 1)][min(j, m - j + 1)].push_back(a[i][j]);
} ll ans = 0; for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
if (!e[i][j].size())continue;
sort(e[i][j].begin(), e[i][j].end());
int t = e[i][j][(e[i][j].size() + 1) / 2 - 1];
for (int k = 0; k < e[i][j].size(); ++k)
ans += abs(t - e[i][j][k]);
}
cout << ans << "\n";
}

星期三 AcWing 3574. 乘积数量

方案一:前缀和维护区间负数个数

看到求区间的问题,会想到前缀和优化

我们可以用前缀和维护 \([1,s_n]\) 区间内的负数个数(因为会影响乘积的正负号的只有负数)

则对于区间 \([s_l,s_r]=v\),若 \(v\) 是奇数,则表示该区间的乘积为负数,反之是正数

  • 若\(s_r−s_{l−1}\)为奇数,则必定是 \(s_r\) 和 \(s_{l−1}\) 一奇一偶

  • 若\(s_r−s_{l−1}\)为偶数,则必定是 \(s_r\) 和 \(s_{l−1}\) 都是偶数或都是奇数

于是我们可以从前往后便利一遍数组,求出前缀和分别为奇数和偶数的个数

然后是一个组合数的问题了,设前缀和为奇数的个数为 \(v_1\) ,前缀和为偶数的个数为 \(v_2\)

区间为正数的子区间个数为 \(C^1_{v1}+C^1_{v2}\)

区间为负数的子区间个数为 \(C^1_{v1}×C^1_{v2}\)

int n;
int s[N];
int s0, s1;
void solve() {
cin >> n;
s0 ++ ;
for (int i = 1; i <= n; ++ i) {
int x;
cin >> x;
s[i] = s[i - 1] + (x < 0);
if (s[i] & 1) ++ s1;
else ++ s0;
}
cout << (LL)s0 * s1 << " " << (LL)s0 * (s0 - 1) / 2 + (LL)s1 * (s1 - 1) / 2 << endl;
}

方案二:DP

DP[i] 表示以 i 结尾的区间有多少个含奇数个负数

  • 则若 xs[i] < 0,则接到 i - 1 含偶数个负数的区间上
  • 否则,则接到 i - 1 含奇数个负数的区间上

但容易发现 \(dp_i\) 仅和前一项相关,所以采用滚动数组

const int N = 2e5 + 10;
int a[N], c[2];
ll cnt0, cnt1;
void solve() {
int n; cin >> n;
for (int i = 1; i <= n; ++i)
cin >> a[i];
int v = 1;
c[v]++;
for (int i = 1; i <= n; ++i) {
if (a[i] < 0) v ^= 1;
cnt0 += (ll)c[v];
cnt1 += (ll)c[v ^ 1];
c[v]++;
}
cout << cnt1 << " " << cnt0 << '\n';
}

星期四 AcWing 3580. 整数配对

没什么好讲的,排序,累加即可

void solve() {
int n; cin >> n;
int a[n + 1], cnt = 0;
for (int i = 1; i <= n; ++i)cin >> a[i];
sort(a + 1, a + 1 + n);
for (int i = 2; i <= n; i += 2)cnt += a[i] - a[i - 1];
cout << cnt ;
}

星期五 AcWing 3583. 整数分组

先对数组按升序排序,然后记录每个数符合条件的最左侧点下标,然后再用DP优化

  • \(f(i,j) = max(f(i,j),f(L_i-1,j-1) + i - L[i] + 1)\)

输出 \(f[n][k]\) 即可

const int N = 5e3 + 10;
int f[N][N], n, a[N], L[N], k;
void solve() {
cin >> n >> k;
for (int i = 1; i <= n; ++i)cin >> a[i];
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; ++i) {
int p = i;
while (p > 1 && a[p - 1] >= a[i] - 5) p--;
L[i] = p;
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= k; ++j)f[i][j] = f[i - 1][j];
for (int j = 1; j <= k; ++j)
f[i][j] = max(f[i][j], f[L[i] - 1][j - 1] + i - L[i] + 1);
}
cout << f[n][k] << "\n";
}

Week 4

星期三 AcWing 3617. 子矩形计数

简单的前缀和累加

using ll = long long;
ll a[40001], b[40001], n, m, i, j, k, ans = 0;
void solve() {
cin >> n >> m >> k;
for (i = 0; i < n; i++) {cin >> a[i]; if (a[i]) a[i] += a[i - 1];}
for (i = 0; i < m; i++) {cin >> b[i]; if (b[i]) b[i] += b[i - 1];}
for (i = 1; i <= n; i++)
if (k % i == 0) {
ll u = i, v = k / i, x = 0, y = 0;
for (j = 0; j < n; j++) if (a[j] >= u) x++;
for (j = 0; j < m; j++) if (b[j] >= v) y++;
ans += x * y;
}
cout << ans;
}

星期四 AcWing 3624. 三值字符串

利用双指针维护最小长度

const int inf = 0x3f3f3f3f;
void solve() {
string s; cin >> s;
int cnt[4] = {0};
int l = 0, ans = inf;
for (int i = 0; i < (int)s.size(); ++i) {
cnt[s[i] - '0']++;
while (cnt[1] and cnt[2] and cnt[3]) {
cnt[s[l] - '0']--;
ans = min(ans, i - l + 1);
++l;
}
}
cout << (ans == inf ? 0 : ans) << "\n";
}

星期五 AcWing 3629. 同心圆涂色

模拟即可,注意 PI 的取值

const double pi = 3.1415926535897932384626433832795;
bool cmp(int a, int b) {return a > b;}
void solve() {
int n; cin >> n;
int r[n];
for (int i = 0; i < n; ++i)cin >> r[i];
sort(r, r + n, cmp);
double ans = 0.0;
int i;
for (i = 1; i < n; i += 2) {
ans += pi * (r[i - 1] * r[i - 1] - r[i] * r[i]);
}
if (i == n)ans += pi * r[i - 1] * r[i - 1];
printf("%.06lf", ans);
}

Week 5

星期一 AcWing 3636. 数组延伸

const int N = 1e5 + 10, mod = 1e9 + 7;
ll n, x;
ll a[N];
void solve() {
cin >> n >> x;
for (int i = 1; i <= n; ++i)cin >> a[i];
ll sum = 0, psum = 0;
//分别代表一开始的数组和,可以向外扩展最小次数的那个数之前的和
int cnt = N;
//最小向外拓展次数
for (int i = 1; i <= n; ++i) {
sum += a[i];
int c = 0;
for (int j = a[i]; j % x == 0; j /= x)c++;
if (c < cnt)cnt = c, psum = sum - a[i];
}
//答案就是一开始的数组和加上向外拓展次数*数组和,再加上截止到向外拓展次数最小的那个数之前的和(到这个数开始,就不是完整的拓展了)
cout << sum * (cnt + 1) + psum << endl;
}

星期二 AcWing 3646. 分水果

最少 (0,0,1) 、(0,1,0)、(1,0,0),至多 (1,1,1)

所以特判情况即可

void solve() {
int a[3];
for (int i = 0; i < 3; ++i)cin >> a[i];
int ans = 0;
if (a[0])ans++, a[0]--;
if (a[1])ans++, a[1]--;
if (a[2])ans++, a[2]--; sort(a, a + 3);
if (a[2] and a[1])ans++, a[2]--, a[1]--;
if (a[2] and a[0])ans++, a[2]--, a[0]--;
if (a[0] and a[1])ans++, a[0]--, a[1]--; if (a[0] and a[1] and a[2])ans++;
cout << ans << "\n";
}

星期三 AcWing 3655. 楼层

数学 or 模拟

void solve() {
int n, x;
cin >> n >> x;
if (n <= 2)cout << 1 << "\n";
else cout << (n - 2 + x - 1) / x + 1 << "\n";
// cout << ((n-3)/x+2) << endl;
}

星期五 AcWing 3664. 数组补全

贪心

找比y小的个数,一定不能超过中位数位置,然后左置1,右置y

void solve() {
int n, k, p, x, y, tot = 0, a, d = 0, i = 0, l, m;
cin >> n >> k >> p >> x >> y;
for (; i < k; tot += a, d += (a < y), i++)cin >> a;
l = n / 2 - d < n - k ? n / 2 - d : n - k;
m = n - k - l;
if (l < 0 || tot + l + m * y > x)cout << -1;
else {
while (m--)cout << y << ' ';
while (l--)cout << 1 << ' ';
}
}

Week 6

星期一 AcWing 3672. 数组重排

i - a[i] != j - a[j]

等价于 i - j != a[i] - a[j]

只需要逆序排列即可

void solve() {
int n; cin >> n;
vector<int>a(n);
for (int &x : a)cin >> x;
sort(a.begin(), a.end(), greater<int>());
for (int i = 0; i < n; ++i)cout << a[i] << " ";
cout << '\n';
}

星期二 AcWing 3679. 素数矩阵

4 1 0 0 0 0 0
0 4 1 0 0 0 0
0 0 4 1 0 0 0
0 0 0 4 1 0 0
0 0 0 0 4 1 0
0 0 0 0 0 4 1
1 0 0 0 0 0 4
void solve() {
int n; cin >> n;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (i == j)cout << 4 << " ";
else if (j == i + 1) cout << 1 << " " ;
else if (i == n - 1 && j == 0) cout << 1 << " ";
else cout << 0 << " ";
}
cout << endl;
}
}

星期三 AcWing 3686. 移动序列

定位区间,然后计算1,0个数

void solve() {
int n;
cin >> n;
vector<int>a(n);
int cnt1 = 0;
for (int &x : a) {
cin >> x;
if (x == 1)cnt1++;
}
int i = 0, j = n - 1;
while (a[i] == 0) i++; //第一个1的位置
while (a[j] == 0) j--; //最后一个1的位置
cout << j - i + 1 - cnt1 << '\n';
}

星期四 AcWing 3697. 回文子序列

注意:问的是回文子序列,不是子串。

长度大于等于3的回文子序列 等价于 两个相等的元素位置之差大于1

所以:遍历数组,找出两个相等的元素。如果位置之差大于1就输出 YES。

如果遍历完数组,也没找到,就输出 NO。

当然也可以用哈希表记录下元素出现的位置,在 \(O(N)\) 时间内过掉。这个方法可以看看其他题解。

void solve() {
int n; cin >> n;
vector<int>a(n);
for (int &x : a)cin >> x;
bool f = false;
for (int i = 0; i < n and !f; ++i)
for (int j = i + 1; j < n; ++j)
if (a[i] == a[j] and j - i > 1) f = true;
cout << (f ? "YES\n" : "NO\n");
}

Week 7

星期一 AcWing 3705. 子集mex值

通过维护两个变量从0开始,如果有0、1、2、3...这样的直接慢慢向上叠加

const int N = 1e5 + 100;
ll n, a[N];
void solve() {
cin >> n;
for (int i = 0; i < n; ++i)cin >> a[i];
sort(a, a + n);
ll m = 0, k = 0;
for (int i = 0; i < n; ++i) {
if (a[i] == m)m++;
else if (a[i] == k)k++;
}
cout << m + k << endl;
}

星期二 AcWing 3711. 方格涂色

待补

const int N = 1e5+10;
int main(){
int t; scanf("%d", &t);
while (t--){
int n, u, r, d, l;
scanf("%d %d %d %d %d", &n, &u, &r, &d, &l);
int top, bottom, right ,left;
bool f = 0;
top = bottom = right = left = 0; if(u == n) top = 2;
else if(u == n-1) top = 1; if(r == n) right = 2;
else if(r == n-1) right = 1; if(d == n) bottom = 2;
else if(d == n-1) bottom = 1; if(l == n) left = 2;
else if(l == n-1) left = 1; // printf("%d %d %d %d\n",top, bottom, right, left); for(int i = 0; i < 16; i++){
int a[4] = {0,0,0,0}, cnt = 0;
while(i>>cnt){
a[cnt] = (i>>cnt)&1;
cnt++;
}
if(a[0]+a[1] >= top && a[0]+a[1] <= u)
if(a[0]+a[2] >= left && a[0]+a[2] <= l)
if(a[1]+a[3] >= right && a[1]+a[3] <= r)
if(a[2]+a[3] >= bottom && a[2]+a[3] <= d)
f = 1; } if(f) cout << "YES\n";
else cout << "NO\n";
}
}

星期三 AcWing 3720. 数组重排

因为对于每个 ai+bi 都要满足 <=x 这个条件

我们只需要贪心的 使得每个和尽可能的小即可

所以对两个数组 按升序 和 降序 sort 一下即可

void solve() {
int n, x;
cin >> n >> x;
vector<int> A(n, 0), B(n, 0);
for (int i = 0; i < n; ++i)
cin >> A[i];
for (int i = 0; i < n; ++i)
cin >> B[i];
sort(A.begin(), A.end());
sort(B.begin(), B.end(), greater<int>());
bool ok = true;
for (int i = 0; i < n; ++i)
if (A[i] + B[i] > x)
ok = false;
cout << (ok ? "Yes" : "No") << endl;
}

星期四 AcWing 3725. 卖罐头

math

ll _, n, x;
void solve() {
ll l, r;
cin >> l >> r;
ll a = r + 1;
if (l % a >= (a + 1) / 2) cout << "YES\n";
else cout << "NO\n";
}

星期五 AcWing 3729. 改变数组元素

int arr[200001];
int res[200001];
void solve() {
int n, i, mn = 1e9;
cin >> n;
for (i = 1; i <= n; i++) cin >> arr[i];
for (i = n; i >= 1; i--) {
mn = min(mn, i - arr[i]);
res[i] = (mn < i);
}
for (i = 1; i <= n; i++) cout << res[i] << " ";
cout << endl;
}

Week 8

星期一 AcWing 3730. 寻找序列

由于题目保证 \(a_i \not= b_i \not = c_i\)所以直接逐位判断选什么即可,时间复杂度 \(\mathcal{O}(n)\)

void solve() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
vector<int> b(n);
for (int i = 0; i < n; i++) cin >> b[i];
vector<int> c(n);
for (int i = 0; i < n; i++) cin >> c[i];
vector<int> p(n, -1);
for (int i = 0; i < n; i++) {
p[i] = a[i];
if (p[i] == p[(i + 1) % n] || p[i] == p[(i + n - 1) % n]) {
p[i] = b[i];
if (p[i] == p[(i + 1) % n] || p[i] == p[(i + n - 1) % n]) {
p[i] = c[i];
}
}
}
for (int i = 0; i < n; i++) {
if (i > 0) cout << " ";
cout << p[i];
}
cout << '\n';
}

星期二 AcWing 3731. 序列凑零

ll _, n;
void solve() {
cin >> n;
int a[n + 1];
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < n; i += 2) cout << a[i + 1] << ' ' << -a[i] << ' ';
cout << endl;
}

星期三 AcWing 3732. 矩阵复原

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
const int N = 510, M = N * N;
int n, m, k;
int g[N][N];
PII pos[M];
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
int x;
cin >> x;
pos[x].y = j;
}
}
for (int i = 1; i <= m; ++ i) {
for (int j = 1; j <= n; ++ j) {
int x;
cin >> x;
pos[x].x = j;
}
}
for (int i = 1; i <= n * m; ++ i) {
auto &p = pos[i];
g[p.x][p.y] = i;
}
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
cout << g[i][j] << " ";
}
cout << endl;
} }
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int _; for (cin >> _; _--;) solve();
return 0;
}

AcWing 每日一题 - Summer的更多相关文章

  1. 2022-11-14 Acwing每日一题

    本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...

  2. 2022-11-13 Acwing每日一题

    本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...

  3. 2022-11-03 Acwing每日一题

    本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...

  4. 2022-11-16 Acwing每日一题

    本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...

  5. 2022-11-12 Acwing每日一题

    本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...

  6. 2022-11-11 Acwing每日一题

    本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...

  7. 2022-11-10 Acwing每日一题

    本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...

  8. 2022-11-09 Acwing每日一题

    本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...

  9. 2022-11-08 Acwing每日一题

    本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...

  10. 2022-11-07 Acwing每日一题

    本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...

随机推荐

  1. Kafka 如何保证消息消费的全局顺序性

    哈喽大家好,我是咸鱼 今天我们继续来讲一讲 Kafka 当有消息被生产出来的时候,如果没有指定分区或者指定 key ,那么消费会按照[轮询]的方式均匀地分配到所有可用分区中,但不一定按照分区顺序来分配 ...

  2. 不要用第三方日志包了Microsoft.Extensions.Logging功能就很强大

    在.NET中,Microsoft.Extensions.Logging是一个广泛使用的日志库,用于记录应用程序的日志信息.它提供了丰富的功能和灵活性,使开发人员能够轻松地记录各种类型的日志,并将其输出 ...

  3. 海上液化天然气 LNG 终端 | 图扑数字孪生

    关于 LNG 液化天然气 (Liquefied Natural Gas,简称 LNG) 在能源转型过程中被广泛认可为相对较清洁的能源选择. 相对于传统的煤炭和石油燃料,LNG 的燃烧过程产生的二氧化碳 ...

  4. Pattern类和Matcher类的使用

    1.先看好数据源 先将一个String对象确定为程序要对其进行操作的数据源. String b="hello,good morning"; 2.建立Pattern类的对象 Stri ...

  5. 数据库的连接用Java

    第一步注册驱动 Class.forName("com.mysql.cj.jdbc.Driver"); 第二步创建用户密码,和具体的url static String name = ...

  6. serdes与PCIE的区别

    serdes和PCIE是两种非常常见的总线.因为PCIE也是差分信号传输,所以做硬件时比较难区别PCIE和serdes的具体差异点. 两者之间的区别主要表现在以下几点: 1.PCIE使用了SERDES ...

  7. 高效的 Json 解析框架 kotlinx.serialization

    一.引出问题 你是否有在使用 Gson 序列化对象时,见到如下异常: Abstract classes can't be instantiated! Register an InstanceCreat ...

  8. HDU 4787 GRE Revenge

    Now Coach Pang is preparing for the Graduate Record Examinations as George did in 2011. At each day, ...

  9. 校验码——循环校验码CRC,海明校验码

  10. bash shell笔记整理——tail命令

    作用 Print the last 10 lines of each FILE to standard output. With more than one FILE, precede each wi ...