思路:

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 条评论

目前还没有评论...