先放个链接:https://codeforc.es/contest/1397
中规中矩的一场比赛吧,但没有AK...考场最后一题没过,赛后想想主要原因还是D题意看错,(英文不好),导致打得很慢(同样A4题,有人rk30,我rk400)
写个简单题解吧,重点讲一下C和E
A题:送分题,没什么好说的,判一下字母数是否平均分成n份就做完了
/*A. Juggling Letters*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
char str[1010];
int cnt[27];
int main()
{
int t;
cin >> t;
while(t--){
memset(cnt,0,sizeof(cnt));
int n;
scanf("%d",&n);
for(int i = 1; i <= n; ++i){
scanf("%s",str+1);
int len = strlen(str+1);
for(int j = 1; j <= len; ++j)
cnt[str[j] - 'a']++;
}
bool flag = true;
for(int i = 0; i <= 'z' - 'a'; ++i){
if(cnt[i] % n) flag = false;
}
if(flag) puts("YES");
else puts("NO");
}
return 0;
}
B题依然送分,题面看着很可怕,但其实我们可以意识到c^n次方非常大(即有很多情况是可以提前判掉的),所以可以暴枚这个数组,然后有个显然的贪心就是给定两个数组a,b,要最小化∑|ai -bi|,就要把a,b排序后按位减
/*B. Power Sequence*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
const int maxn = 1e5 + 10;
ll a[maxn],p[maxn];
int read(){
char c = getchar();
int x = 0;
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar();
return x;
}
const ll inf = 1e15;
int main()
{
int n = read();
ll ans = 2e18;
for(int i = 0; i < n; ++i)
a[i] = read();
sort(a,a+n) ;
ll x = 1;
while(1){
bool flag = false;
p[0] = 1;
for(int i = 1; i < n; ++i){
p[i] = p[i-1] * x;
if(p[i] >= inf){
flag = true;
break;
}
}
if(flag) break;
x++;
ll res = 0;
for(int i = 0; i < n; ++i)
res += abs(p[i] - a[i]);
ans = min(ans,res);
}
printf("%lld
",ans);
return 0;
}
C题比较有意思,为什么构造是3次?我们可以先把an搞成0(这个是显然可以的,因为任何数都是1的倍数),然后分别对1~n-1,1~n搞,问题就转化为求a * (n-1) - b * n = -a[i]
因为对于任意n,都有gcd(n,n-1) = 1,所以根据Bezout定理,这个不定方程一定有整数解,拓欧求一下即可
/*C. Multiples of Length*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const int maxn = 1e5 + 10;
int a[maxn];
ll b[maxn];
int read(){
int f = 1;
int x = 0;
char c = getchar();
while(c < '0' || c > '9') f = (c == '-')?-1:f,c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar();
return x * f;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b == 0){
x = 1,y = 0;
return a;
}
ll d = exgcd(b,a%b,x,y);
ll z = x;x = y;y = z - (a / b) * y;
return d;
}
int main()
{
int n = read();
for(int i = 1; i <= n; ++i)
a[i] = read();
if(n == 1){
printf("1 1
");
printf("%d
",-1*a[1]);
printf("1 1
0
");
printf("1 1
0
");
return 0;
}
if(n == 2){
printf("1 1
%d
",-1*a[1]);
printf("2 2
%d
",-1*a[2]);
printf("1 1
0
");
return 0;
}
if(n == 3){
printf("1 1
%d
",-1*a[1]);
printf("2 2
%d
",-1*a[2]);
printf("3 3
%d
",-1*a[3]);
return 0;
}
ll x = 0,y = 0;
exgcd(n,n-1,x,y);
printf("1 1
%d
",-1*a[1]);
printf("%d %d
",2,n);
for(int i = 2; i <= n; ++i){
printf("%lld ",1ll * x * (n - 1) * a[i]);
}
puts("");
printf("%d %d
",1,n);
for(int i = 1; i <= n; ++i){
if(i == 1) printf("%d ",0);
else printf("%lld ",1ll * y * n * a[i]);
}
return 0;
}
D题不说了,简单贪心,每次取能取的最大,就过了
/*Stoned Games*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define ll long long
int a[110];
struct Num{
int id,v;
};
bool operator < (Num A,Num B) {
return A.v < B.v;
}
priority_queue<Num>q;
int read(){
char c = getchar();
int x = 0;
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar();
return x;
}
int main()
{
int t = read();
while(t--){
int n = read();
while(!q.empty()) q.pop();
for(int i = 1; i <= n; ++i)
a[i] = read(),q.push(Num{i,a[i]});
int cnt = 0;
int lst = 0;
while(1){
if(q.empty()) break;
Num now = q.top();Num A;
if(now.id == lst){
//if(q.empty()) break;
q.pop();
if(q.empty()) break;
A = q.top();
q.pop();
lst = A.id;
if(A.v >= 2)
q.push(Num{A.id,A.v-1});
q.push(now);
}
else{
lst = now.id;
q.pop();
if(now.v >= 2)
q.push(Num{now.id,now.v-1});
}
cnt++;
}
if(cnt & 1) puts("T");
else puts("HL");
}
return 0;
}
E题比较有意思,对于这种有一堆操作的,一般都只有几种操作有用,其实可以发现,对于一组怪,要么直接全部杀死,要么就只有boss剩1滴血,又因为每组怪都要处理,所以最优解钟最多只有前一个的怪还没有打完(即boss剩一滴血的情况),所以可以根据这个性质DP,具体看代码,有注释
/*E Monster Invader*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const int maxn = 1e6 + 10;
ll f[maxn][2];/*f[i][0] (1~i has finished) f[i][1] (only the boss of i hasn't finished)*/
ll A[maxn],B[maxn],C[maxn];
ll read(){
char c = getchar();
ll x = 0;
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar();
return x;
}
int a[maxn];
int main()
{
int n = read();
ll r1 = read(),r2 = read(),r3 = read(),d = read();
for(int i = 1; i <= n; ++i) a[i] = read();
memset(f,0x3f,sizeof(f));
f[0][0] = 0;
for(int i = 1; i <= n; ++i){
A[i] = min(min(r2,r1),r3);/*一击必杀最小代价*/
B[i] = min(r3,r1) * a[i] + r3;/*直接清理掉的最小代价*/
C[i] = min((min(r3,r1) * a[i] + r1),r2);/*剩boss一滴血的最小代价*/
}
for(int i = 1; i <= n; ++i) {
if(i == 1)
f[i][0] = B[i],f[i][1] = f[i-1][0] + C[i];
else{
int k = (i == n)?2:3;
f[i][0] = min(min(f[i-1][0] + B[i] + d,f[i-1][0] + C[i] + 3 * d + A[i]),min(f[i-1][1] + k * d + B[i] + A[i-1],
f[i-1][1] + 3 * d + C[i] + A[i-1] + A[i]));
f[i][1] = f[i-1][0] + C[i] + d;
}
//printf("f[%d][0] = %lld f[%d][1] = %lld
",i,f[i][0],i,f[i][1]);
}
printf("%lld
",f[n][0]);
return 0;
}