题意 将 1 1 1 经过最少次的操作变成 n n n,对于一个数 x x x 有以下三种操作
题解 反过来看,从 n n n 变换到 1 1 1,先进行 1 ∼ 1 0 6 1\sim 10^6 1∼106 区间内的预处理,随后使用 H a s h m a p Hash~map Hash map 记忆化搜素
因为进行两次操作 x − − x-- x−− 和一次 x / = 2 x/=2 x/=2 是亏的,等价于 x / = 2 x/=2 x/=2 和 x − − x-- x−−;同理也不能连续进行三次 x − − x-- x−− 再进行一次 x / = 3 x/=3 x/=3
const int N = 1e6 + 2;
unordered_map<ll, int> mp;
int f[N];
void init() { // 预处理
memset(f, 0x3f, sizeof f);
f[1] = 0;
for (int i = 1; i < N; i ++) {
if (i * 2 < N) f[i * 2] = min(f[i * 2], f[i] + 1);
if (i * 3 < N) f[i * 3] = min(f[i * 3], f[i] + 1);
if (i + 1 < N) f[i + 1] = min(f[i + 1], f[i] + 1);
}
}
ll dfs(ll n) {
if (n < N) return f[n];
if (mp.count(n)) return mp[n]; // 记忆化
return mp[n] = min(
dfs(n / 2) + n % 2 + 1,
dfs(n / 3) + n % 3 + 1
);
}
int main() {
init();
FastIO
Cases
{
ll n; cin >> n;
cout << dfs(n) << endl;
}
return 0;
}
其实不用预处理也行,但是要特判 n < 2 n<2 n<2 时 r e t u r n 0 return~0 return 0
unordered_map<ll, int> mp;
ll dfs(ll n) {
if (n < 2) return 0;
if (mp.count(n)) return mp[n]; // 记忆化
return mp[n] = min(
dfs(n / 2) + n % 2 + 1,
dfs(n / 3) + n % 3 + 1
);
}
int main() {
init();
FastIO
Cases
{
ll n; cin >> n;
cout << dfs(n) << endl;
}
return 0;
}
题意 将数组 [ a 1 , a 2 , a 3 , . . . , a n ] [a_1,a_2,a_3,...,a_n] [a1,a2,a3,...,an] 分割成 n n n 维数组每组大小为 l l l,即 [ [ a 1 , . . . , a l ] , [ a l + 1 , . . . , a 2 l ] , . . . ] [[a_1,...,a_l],[a_{l+1},...,{a_{2l}}],...] [[a1,...,al],[al+1,...,a2l],...]
void solve() {
string s, str;
cin.ignore();
getline(cin, s);
int n, l; cin >> n >> l;
int cnt = 0, num = 0;
for (int i = 0; i < s.size(); i ++) {
char c = s[i];
if (c == ',' || c == ']') cnt ++;
if (cnt == l) {
cout << "[" << str << ']';
num ++, i ++, cnt = 0, str = "";
if (num != n) cout << ", ";
}
else str += c;
}
cout << ']' << endl;
}
题意 有 n n n 个人,每个人 a i a_i ai 个硬币,每次选两人其中一人给另一个人一个硬币,如果某人没有硬币则退出游戏,问最后进行轮数的期望值(保证为整数)
题解 打表猜结论♂️♂️♂️
对于每一轮两个人,选择哪个人给硬币的概率为 50 % 50\% 50%,则游戏轮数的期望为 f ( m , n ) = 1 + 50 % ⋅ f ( m + 1 , n − 1 ) + 50 % ⋅ f ( m − 1 , m + 1 ) f(m,n)=1+50\%·f(m+1,n-1)+50\%·f(m-1,m+1) f(m,n)=1+50%⋅f(m+1,n−1)+50%⋅f(m−1,m+1)
// 打表 code
double dfs(ll m, ll n, ll dep) {
if (dep == 40 || !m || !n) return 0;
return 1 + dfs(m + 1, n - 1, dep + 1) / 2 + dfs(m - 1, n + 1, dep + 1) / 2;
}
cout << dfs(m, n, 0) << endl;
1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|
1 | 1 | 2 | 3 | 3.99921 | 4.9852 | 5.91537 |
2 | 4 | 5.99872 | 7.97463 | 9.8475 | ||
3 | 8.9704 | 11.8098 |
根据打表结果猜测 f ( n , m ) = n ⋅ m f(n,m)=n·m f(n,m)=n⋅m
对于三个人,由样例 in:1 1 1, out:3
猜测是 a 1 a 2 + a 2 a 3 + a 3 a 1 a_1a_2+a_2a_3+a_3a_1 a1a2+a2a3+a3a1
再推广到 n n n 个人,两两相乘然后相加即可,从 O ( n 2 ) O(n^2) O(n2) 优化到 O ( n ) O(n) O(n),答案即为 ∑ 1 ≤ i ≤ j ≤ n a i a j = ∑ i = 1 n a i ⋅ ( s u m − a i ) \sum_{1\le i\le j\le n}a_ia_j=\sum_{i=1}^na_i·(sum-a_i) ∑1≤i≤j≤naiaj=∑i=1nai⋅(sum−ai)
using lll = __int128;
void write(lll x) {
if (x > 9) write(x / 10);
cout << char(x % 10 + '0');
}
void solve() {
int n; cin >> n;
vector<int> a(n);
lll res = 0, sum = 0;
for (auto &x: a) cin >> x, sum += x;
for (auto i : a) res += (sum - i) * i;
write(res / 2); cout << endl;
}