- 题解
Day4 思路和T3代码
- @ 2024-10-5 15:52:27
思路:
T1:
for i枚举 l~r 除数:
for j枚举 n 个被除数:
更新最小和,同时记录 ans = i
cout << ans;
时间复杂度: O(n^2) 9*10^6
T2:
a*b = xxxx000...0000 使得ans的末尾至少有k个0
假设有一个数Q:10000...0000(k个0)
a*b 一定是Q的倍数
x*b = Q 使得x尽可能大, x = gcd(Q,a);
Q = 1000
a = 30
b = 100
b = Q/gcd(Q,a);
typedef long long ll;
ll gcd(ll a, ll b)
{
if (a % b == 0) return b;
return gcd(b, a%b);
}
T3:
1.被修改的节点,只会影响它的父节点和它自己
2.给定一个字符集合,如何判断这个字符集合是否可以构成回文?
s1 = {a,a,a,b,b,c,c,d}
s2 = {a,a,a,a,b,b,c,c,d,d}
s3 = {a,b,b,c,c,d}
s4 = {a,a,b,c,c,b}
若这个字符集要能构成回文,那么出现次数为奇数次的字符数,<=1
cnt[i][j]; // 以i号结点作为根节点的树中,字符j出现的次数
book[i] = 1; // 表示i号节点是ok的
1.数据存储
如何存下这个树,由于给出的数据是层序遍历,直接输入数组即可
假设根节点下标是i,那么左子树下标是2*i,右子树下标是2*i+1
char c[N];
for (int i = 1; i <= n; i++) cin >> c[i];
2.给定一个字符集合,如何判断这个字符集合是否可以构成回文?
若这个字符集要能构成回文,那么出现次数为奇数次的字符数,<=1
3.如何统计出i号节点作为根的这棵树,每个字符出现的次数
字符出现次数 = i本身 + 2*i的左子树 + 2*i+1的右子树
T4:
1 4 3 2
cnt1 = 3
cnt2 = 3
n个数字,有多少对数对?
C(n,2) = n*(n-1)/2
(x,y) = n*(n-1)/2
顺序对:sum = n*(n-1)/4
1 放到 1 :n-1 sum -= (n-1)
2 放到 2 : n-2 sum -= (n-2)
3 放到 3 :n-3 sum -= (n-3)
...
i 放到 i : n-i sum < n-i --> 放不下了
sum
x 放到 x 的位置可以产生 n-x对顺序对
当前i的位置药房的数 :x = n - 剩下的数字
接下来只需要把逆序对按字典序填充即可
n=8
sum = 4*3/4 = 3
a = [1,4,3,2]
sum = 0
cnt[i][j]; // 以i号结点作为根节点的树中,字符j出现的次数
book[i] = 1; // 表示i号节点是ok的
1.数据存储
如何存下这个树,由于给出的数据是层序遍历,直接输入数组即可
假设根节点下标是i,那么左子树下标是2*i,右子树下标是2*i+1
char c[N];
for (int i = 1; i <= n; i++) cin >> c[i];
2.给定一个字符集合,如何判断这个字符集合是否可以构成回文?
若这个字符集要能构成回文,那么出现次数为奇数次的字符数,<=1
3.如何统计出i号节点作为根的这棵树,每个字符出现的次数
字符出现次数 = i本身 + 2*i的左子树 + 2*i+1的右子树
【参考代码】
#include<bits/stdc++.h>
#define io(x); freopen(x".in", "r", stdin), freopen(x".out", "w", stdout);
using namespace std;
const int N = 1e5 + 10;
int n, q, cnt[N][30], book[N], res;
char c[N];
void dfs(int i)
{
if (2*i <= n)
{
dfs(i*2);
for (int j = 0; j < 26; j++) cnt[i][j] += cnt[2*i][j];
}
if (2*i+1 <= n)
{
dfs(i*2+1);
for (int j = 0; j < 26; j++) cnt[i][j] += cnt[2*i+1][j];
}
cnt[i][c[i]-'a']++;
int temp = 0;
for (int j = 0; j < 26; j++) temp += (cnt[i][j]%2);
if (temp <= 1)
{
res ++;
book[i] = 1;
}
}
void up(int i, char now, char old)
{
// i i/2 i/4 i/8 ....
while (i)
{
cnt[i][old-'a']--;
cnt[i][now-'a']++;
// 重新统计奇偶性
int temp = 0;
for (int j = 0; j < 26; j++) temp += (cnt[i][j]%2);
if (temp <= 1)
{
if (!book[i]) res++; // 之前不可以,现在可以了
book[i] = 1;
}
else
{
if (book[i]) res--; // 之前可以,现在不行了
book[i] = 0;
}
i/=2; // 更新父节点
}
}
int main()
{
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
cin >> n >> q;
for (int i = 1; i <= n; i++) cin >> c[i];
dfs(1);
cout << res << endl;
while (q--)
{
int x;
char ch;
cin >> x >> ch;
up(x, ch, c[x]); // 节点编号,新字符,旧字符
c[x] = ch;
cout << res << endl;
}
return 0;
}
0 条评论
目前还没有评论...