Atcoder Regular Contest 060 题解
ARC060C. Tak and Cards *1583
简单题。考虑一个非常非常常见的 Trick。把区间平均值为
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MAXN = 55;
LL n, a, A[MAXN], DP[MAXN][5005], delta = 2500;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> a;
for(LL i = 1; i <= n; i ++)
{
cin >> A[i];
A[i] -= a;
}
DP[0][delta] = 1;
for(int i = 1; i <= n; i ++)
{
for(int j = 0; j <= 5000; j ++)
{
if(j >= A[i]) DP[i][j] = DP[i - 1][j] + DP[i - 1][j - A[i]];
else DP[i][j] = DP[i - 1][j];
}
}
cout << DP[n][delta] - 1 << '\n';
return 0;
}
ARC060D. Digit Sum *2261
非常神的题,但是我自己想到了。
根号分治。首先如果
如果
然后做完了,代码不长但根号分治一般都很神。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n, s;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> s;
if(n < s)
{
cout << -1 << '\n';
return 0;
}
for(LL i = 2; i <= (LL)sqrt(n); i ++)
{
LL sum = 0, nn = n;
while(nn > 0)
{
sum += (nn % i);
nn /= i;
}
if(sum == s)
{
cout << i << '\n';
return 0;
}
}
LL minnum = 1e15 + 7;
if(s == n) minnum = min(minnum, n + 1);
for(LL i = 1; i <= sqrt(n); i ++)
{
if((n - s) % i != 0) continue;
LL b = (n - s) / i + 1;
if(b == 1) continue;
LL sum = 0, nn = n;
while(nn > 0)
{
sum += (nn % b);
nn /= b;
}
if(sum == s) minnum = min(minnum, b);
}
if(minnum == 1e15 + 7) cout << -1 << '\n';
else cout << minnum << '\n';
return 0;
}
ARC060E. Tak and Hotels *2154
倍增优化动态规划,我应该还是第一次理解这个东西。朴素的暴力就是暴力枚举,这里不做过多讲解。
考虑正解,设
然后就做完了。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MAXN = 100005;
LL n, A[MAXN], L, Q, DP[MAXN][25];
LL Query(LL a, LL b)
{
LL now = a, ans = 0;
for(LL i = 24; i >= 0; i --)
if(DP[now][i] < b)
{
ans += (1 << i);
now = DP[now][i];
}
return ans + 1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n;
for(LL i = 1; i <= n; i ++) cin >> A[i];
cin >> L;
memset(DP, 0x3f, sizeof(DP));
for(LL i = 1; i <= n; i ++)
{
LL Pos = upper_bound(A + 1, A + n + 1, A[i] + L) - A - 1;
DP[i][0] = Pos;
}
for(LL j = 1; j <= 24; j ++)
for(LL i = 1; i <= n; i ++)
DP[i][j] = DP[DP[i][j - 1]][j - 1];
cin >> Q;
while(Q --)
{
LL a, b;
cin >> a >> b;
if(a > b) swap(a, b);
cout << Query(a, b) << '\n';
}
return 0;
}
ARC060F. Best Representation *2804
Subtask 1:
考虑一个
注意到好串的定义就是之前题目里面的 Power Strings。然后就递推跑 KMP,应该是跑
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 4005;
const int MOD = 1e9 + 7;
string s;
int n, KMP[MAXN], Q[MAXN][MAXN], f[MAXN], g[MAXN];
int main()
{
cin >> s; n = s.length(); s = ' ' + s;
for(int i = 1; i <= n; i ++)
for(int j = i; j <= n; j ++)
Q[i][j] = 1;
for(int i = 1; i <= n; i ++)
{
memset(KMP, 0, sizeof(KMP));
int k = 0;
for(int j = 2; j <= n - i + 1; j ++)
{
while(k > 0 && s[j + i - 1] != s[k + i]) k = KMP[k];
if(s[j + i - 1] == s[k + i]) k ++;
KMP[j] = k;
if(j % (j - KMP[j]) == 0 && j / (j - KMP[j]) >= 2) Q[i][i + j - 1] = 0;
}
}
memset(f, 0x3f, sizeof(f));
f[0] = 0;
for(int i = 1; i <= n; i ++)
{
for(int j = 0; j < i; j ++)
{
if(Q[j + 1][i] == 0) continue;
if(f[j] + 1 == f[i]) g[i] = (g[i] + 1) % MOD;
else if(f[j] + 1 < f[i])
{
f[i] = f[j] + 1;
g[i] = 1;
}
}
}
cout << f[n] << '\n' << g[n] << '\n';
return 0;
}
Subtask 2:
首先特判:
- 如果字符串内的元素全部相等,那么必然要划分成
个串,个数就是 个。 - 如果字符串没有长度
的周期或者 ,那么可以不用划分,最小划分个数就是 ,个数也是 。
后面有一个非常强的结论,我不想证。就是如果存在周期长度
然后怎么计数呢?因为是划分成两段,所以我们很自然的想到枚举分界点,然后看前面一段是不是 Power Strings,然后看后面一段是不是 Power Strings,因为 KMP 跑出的 border 具有对称性,所以可以通过正反串两次 KMP 得出答案。最后判断是
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 500005;
string s, t;
int n, KMP[MAXN], KMP2[MAXN];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> s; n = s.length(); s = ' ' + s;
bool Flag = true;
for(int i = 2; i <= n; i ++) if(s[i] != s[i - 1]) Flag = false;
if(Flag)
{
cout << n << '\n' << 1 << '\n';
return 0;
}
for(int i = n; i >= 1; i --) t += s[i];
t = ' ' + t;
for(int i = 2, j = 0; i <= n; i ++)
{
while(j > 0 && s[i] != s[j + 1]) j = KMP[j];
if(s[i] == s[j + 1]) j ++;
KMP[i] = j;
}
for(int i = 2, j = 0; i <= n; i ++)
{
while(j > 0 && t[i] != t[j + 1]) j = KMP2[j];
if(t[i] == t[j + 1]) j ++;
KMP2[i] = j;
}
if(!KMP[n] || n % (n - KMP[n]) != 0) // 没有循环节
{
cout << 1 << '\n' << 1 << '\n';
return 0;
}
int ans = 0;
for(int i = 1; i < n; i ++)
if((KMP[i] == 0 || i % (i - KMP[i]) != 0) && (KMP2[n - i] == 0 || (n - i) % (n - i - KMP2[n - i]) != 0)) ans ++;
cout << 2 << '\n' << ans << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】