====== CF #643 (div2) ======
cy
==== A. Sequence with Digits ====
**题意**: $a_{n+1} = a_n+MinDig(a_n)*MaxDig(a_n)$,Dig表示十进制表示中的最大的一个数字和最小的一个数字。给出$a_1$和$K$求$a_K$。两个数字都$<=1e18$
**题解**:刚开始的时候没想出什么好办法,想到了如果对于其中某一项,MinDig为0,则后面都是0,但这一项是否一定会出现呢?是否有一种构造使其永远不会出现0?不存在的,我们发现,每一项比前一项最多大$9*9=81$,现在考虑$[1000*(a_i/1000+1),1000*(a_i/1000+1)+99]$这一段区间,显然这段区间所有的数字都含有0这个数位,并且这段区间长度大于81,也就是说,$a_n$只要存在大于这个区间的值,就一定会有一项落到这个区间内,其必含有0,所以可以直接暴力计算$a_1,a_2$…
#include
#include
#include
#include
using namespace std;
typedef unsigned long long ull;
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
ull x, k;
cin >> x >> k;
for (int i = 2; i <= k;i++)
{
ull tem = x;
ull mmin = 9, mmax = 0;
while (tem)
{
ull jkl = tem % 10;
mmin = min(mmin, jkl);
mmax = max(mmax, jkl);
tem /= 10;
}
x += mmin * mmax;
if(mmin == 0 || mmax == 0)
break;
}
cout << x << endl;
}
return 0;
}
==== B. Young Explorers ====
**题解**:直接贪心,没啥好说的
#include
#include
#include
#include
using namespace std;
const int MAX = 2e5 + 100;
int pic[MAX];
int n;
int main() {
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for (int i = 1; i <= n;i++)
scanf("%d", &pic[i]);
sort(pic + 1, pic + 1 + n);
int ans = 0;
int tem = 0;
for (int i = 1; i <= n;i++)
{
tem++;
if (pic[i] == tem)
{
ans++;
tem = 0;
}
}
printf("%d\n", ans);
}
return 0;
}
==== C. Count Triangles ====
**题意**:给定ABCD,($<=5e5$),求出有多少个x,y,z可以组成一个三角形($A<=x<=B<=y<=C<=z<=D$)
**题解**:做的时候脑子不清醒,想错了,分了8类讨论。。。这题官方题解的方法非常好。 用一个大数组$A_i$来表示$x+y=i$的个数,计算数组$A$时,可以枚举x的值,然后用前缀和的方式来计算区间加法,然后对数组A再来一次前缀和,就能求出$x+y<=i$的个数,最后累加C到D之间的答案即可。
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAX = 1e6 + 20;
ll pic[MAX];
int main()
{
int a, b, c, d;
cin >> a >> b >> c >> d;
for (int i = a; i <= b;i++)
{
pic[i + b]++;
pic[i + c + 1]--;
}
for (int i = 1; i < MAX; i++)
pic[i] += pic[i - 1];
for (int i = 1; i < MAX; i++)
pic[i] += pic[i - 1];
ll ans = 0;
for (int i = c; i <= d;i++)
ans += pic[MAX-1] - pic[i];
cout << ans;
}
==== D. Game With Array ====
**题解**:这题很容易构造出来,条件放的太宽了。
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int main()
{
int n, s;
cin >> n >> s;
int mean = s / n;
int lef = s - mean * n + mean;
if (mean > 1)
{
cout << "YES" << endl;
for (int i = 1; i < n;i++)
cout << mean << ' ';
cout << lef << endl;
cout << 1;
}
else
{
cout << "NO" << endl;
}
return 0;
}
==== E. Restorer Distance ====
**题意**:初始有 n 根柱子,每根柱子有一个高度 h[i],现在有三种操作:花费 A 使得某根柱子高度+1、花费 R 使得某根柱子高度-1、花费 M 使得某根柱子高度-1而另一根+1。问最少的花费,使得最终所有柱子高度一样。
**题解**:如果有一个给定的h,那么最终花费很好求,只要求一个前缀和然后二分查找即可。问题在于这个h如何去确定,官方题解给出的答案是,先假设一个h,再给h增加1,观察最终花费的变化,最终发现,最优答案的h一定和某个柱子的砖块数量一样,或者是在均值附近,于是可以nlogn枚举答案,还有一种思路,发现最终答案和h的大小呈二次函数关系,于是三分。
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAX = 1e5 + 20;
ll pic[MAX];
ll sum[MAX];
ll n, a, r, m;
ll cal(ll h)
{
int pos = lower_bound(pic + 1, pic + 1 + n, h) - pic - 1;
ll res = 0;
ll k1 = h * pos - sum[pos];
ll k2 = sum[n] - sum[pos] - h * (n - pos);
res = min(k1, k2);
k1 -= res;
k2 -= res;
res *= m;
res += k1 * a;
res += k2 * r;
return res;
}
int main()
{
cin >> n >> a >> r >> m;
for (int i = 1; i <= n;i++)
{
scanf("%lld", &pic[i]);
}
sort(pic + 1, pic + 1 + n);
m = min(m, a + r);
for (int i = 1; i <= n;i++)
sum[i] = sum[i - 1] + pic[i];
ll ans = 0x3f3f3f3f3f3f3f3f;
ans = min(ans, cal(sum[n] / n));
ans = min(ans, cal(sum[n] / n + 1));
for (int i = 1; i <= n; i++)
ans = min(ans, cal(pic[i]));
cout << ans;
}
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAX = 1e5 + 20;
ll pic[MAX];
ll sum[MAX];
ll n, a, r, m;
ll cal(ll h)
{
int pos = lower_bound(pic + 1, pic + 1 + n, h) - pic - 1;
ll res = 0;
ll k1 = h * pos - sum[pos];
ll k2 = sum[n] - sum[pos] - h * (n - pos);
res = min(k1, k2);
k1 -= res;
k2 -= res;
res *= m;
res += k1 * a;
res += k2 * r;
return res;
}
int main()
{
cin >> n >> a >> r >> m;
for (int i = 1; i <= n;i++)
{
scanf("%lld", &pic[i]);
}
sort(pic + 1, pic + 1 + n);
m = min(m, a + r);
for (int i = 1; i <= n;i++)
sum[i] = sum[i - 1] + pic[i];
ll ans = 0x3f3f3f3f3f3f3f3f;
int L = 0, R = 1e9;
while (L < R)
{
int mid = (L + R) >> 1;
int mmid = (mid + R) >> 1;
if (mid == mmid)
break;
if (cal((ll)mid) < cal((ll)mmid))
R = mmid;
else
L=mid;
}
for (int i = L; i <= R;i++)
ans = min(ans, cal((ll)i));
cout << ans;
}