然后代码中前缀和数组的定义与上面的题解有一点不一样(而且上面的题解好像把 j j j写成 i i i了)。含义如下
s u m [ e ] [ i ] = ∑ e ′ ( ∏ j < i [ e j ′ = e j ] ∏ j ≥ i [ e j ′ ≤ e j ] d p [ e ′ ] ) sum[e][i]=\sum_{e'}\left(\prod_{jsum[e][i]=e′∑(j<i∏[ej′=ej]j≥i∏[ej′≤ej]dp[e′])
#include
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<int> vec;
const int mod = 1e9 + 7;
const int MAXN = 200005;
const ULL sd = 19260817;
const LL lim = (LL)(1e12);
map<ULL, int>ID;
ULL hsh(vec V) { sort(V.begin(), V.end()); ULL re = 0; for(auto x : V) re = re * sd + x; return re; }
inline int qpow(int a, int b) { int re = 1; for(; b; b>>=1, a=1ll*a*a%mod)if(b&1)re=1ll*re*a%mod; return re; }
char ss[30];
struct big {
LL a[2];
big(int x = 0){ a[0] = x, a[1] = 0; }
big operator *=(const int x) {
a[0] *= x; a[1] *= x;
a[1] += a[0]/lim, a[0] %= lim;
return *this;
}
bool operator <(const big &o)const { return a[1] == o.a[1] ? a[0] < o.a[0] : a[1] < o.a[1]; }
int operator %(const int x) { return (a[0] % x + a[1] % x * lim) % x; }
void operator /= (const int x) { (a[0] += a[1] % x * lim) /= x, a[1] /= x; }
bool read() {
if(!~scanf("%s", ss)) return 0;
int len = strlen(ss); a[0] = a[1] = 0;
for(int i = 0; i*12 < len; ++i)
for(int j = min(12, len-i*12); j; --j) a[i] = a[i] * 10 + ss[len-i*12-j] - '0';
return 1;
}
}Mx;
int pr[25] = { 0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71 }, K = 19, cnt;
pair<big, vec>S[MAXN];
void dfs(big x, int k, int pre, vec V) {
S[++cnt] = make_pair(x, V); V.push_back(0);
for(int i = 1; i <= pre && (x *= pr[k]) < Mx; ++i)
V.back() = i, dfs(x, k+1, i, V);
}
int sum[MAXN][21], ans[MAXN];
void pre() {
Mx.a[1] = lim, Mx.a[0] = 1;
dfs(big(1), 1, 80, vec(0));
sort(S + 1, S + cnt + 1);
for(int i = 1; i <= cnt; ++i) ID[hsh(S[i].second)] = i;
for(int i = 2; i <= cnt; ++i) {
for(int j = S[i].second.size()-1; ~j; --j) {
sum[i][j] = sum[i][j+1];
if(S[i].second[j]) {
vec tmp = S[i].second; --tmp[j];
sum[i][j] = (sum[i][j] + sum[ID[hsh(tmp)]][j]) % mod;
}
}
int d = 1; for(int x : S[i].second) d *= x+1;
ans[i] = 1ll * (d + sum[i][0]) * qpow(d-1, mod-2) % mod;
for(int j = 0; j <= K; ++j) sum[i][j] = (sum[i][j] + ans[i]) % mod;
}
}
int main () {
freopen("div.in", "r", stdin);
freopen("div.out", "w", stdout);
pre(); big n; int m;
while(n.read()) {
scanf("%d", &m); vec a;
for(int i = 1, x; i <= m; ++i) {
scanf("%d", &x); int mi = 0;
while(n % x == 0) ++mi, n /= x;
a.push_back(mi);
}
printf("%d\n", ans[ID[hsh(a)]]);
}
}
考试时以为写了正解,其实就差了一个情况没考虑,只有40…
发现只要出现连续3个 # \# #," # # # \#\#\# ###"那么一定无法走过去。就可以不管后面的了。
那么现在考虑连续2个 # \# #,如果要走过去,一定是" # # ∗ \#\#* ##∗",然后在前面放一个 ∗ * ∗才能走过去。
如果是1个 # \# #,要么是" # ∗ \#* #∗"直接走过去,要么就在 # \# #前面放一个 ∗ * ∗再走过去。
而且可以发现,如果手里有2个 ∗ * ∗,走过1个 # \# #对我们来说其实是“如履平地”的。因为可以在前面放个,然后过去在后面放个,再走回来取走前面的 ∗ * ∗,这样我们没有损失。
然后对于连续2个 # \# #的情况我们必须要留一个 ∗ * ∗在原地。
那么我们用" # # \#\# ##"分割整个序列为若干块,从左往右走,如果手里的 ∗ * ∗能达到2块,那么我们就能畅通无阻地走过 # \# #。所以从最开始的块到当前块的所有 ∗ * ∗都能拿到,但还要减去 # # \#\# ##的代价。
如果向右走走不动了就break就行了。答案就是手里的 ∗ * ∗取 max \max max。
但还有一种情况未考虑,就是 ∗ # . . . ∗ *\#...* ∗#...∗这种情况,我们如果只往右走,手里的 ∗ * ∗数不能达到2个,但是可以往回走取掉前面的 ∗ # *\# ∗#的 ∗ * ∗。这种情况只需要设一个变量作为标记就行了。
具体细节可以看代码。
#include
using namespace std;
const int MAXN = 400005;
int n, m, sum[MAXN], L[MAXN], R[MAXN];
char s[MAXN];
int main () {
freopen("tower.in", "r", stdin);
freopen("tower.out", "w", stdout);
int T; scanf("%d", &T);
while(T--) {
scanf("%s", s+1); n = strlen(s+1);
m = 0; s[n+1] = '#';
for(int i = 1; i <= n; ++i) sum[i] = sum[i-1] + (s[i] == '*');
for(int i = 1, j; i <= n; i = j+2) {
if(i > 1 && s[i] != '*') break; //除了第一块 判断是不是 ##*
L[++m] = i;
for(j = i; j <= n && !(s[j] == '#' && s[j+1] == '#'); ++j);
R[m] = j-1;
}
int now = 1, ans = 0;
for(int x = 1; x <= m; ++x) {
--now; if(now < 0) break; //减去 *## 放在前面的那个*
bool flg = 0; //用来判断前面是否有 *# 的标记
for(int i = L[x]; i <= R[x]; ++i) {
if(s[i] == '*') {
ans = max(ans, ++now);
if(now >= 2 || now == 1 && flg) break;
}
if(s[i] == '#') {
if(s[i+1] == '*') { flg = 0; continue; } //#* 的情况 清标记
--now; flg = 1; //*# 的情况 加标记
if(now < 0) break;
}
}
if(now >= 2 || now == 1 && flg) now = sum[R[x]] - (x-1); //判断能否如履平地
ans = max(ans, now);
}
printf("%d\n", ans);
}
}
#include
using namespace std;
const int MAXN = 10005;
const int MAXn = 5005;
int N, n, K, a[MAXN], sum[MAXN], all, dp[MAXN][2], q[MAXN];
int main () {
freopen("subsegment.in", "r", stdin);
freopen("subsegment.out", "w", stdout);
scanf("%d%d", &n, &K); N = 2*n-1;
for(int i = 1; i <= N; i+=2) scanf("%d", &a[i]);
if(a[1] < 0) a[1] = 0;
if(a[N] < 0) a[N] = 0;
for(int i = 1; i <= N; ++i) sum[i] = sum[i-1] + ((i&1)?a[i]:K), all += a[i];
memset(dp, 0x3f, sizeof dp); dp[0][0] = 0;
int now = 1, ans = 0;
for(int j = 0; j < n; ++j) { now ^= 1;
int l = 0, p = 0, s = 1, t = 0;
for(int i = 1; i <= N; ++i) { dp[i][now] = 0x3f3f3f3f;
if(a[i] < 0) l = i, p = i-1, s = 1, t = 0;
if(l) dp[i][now] = max(dp[l-1][now], sum[i]-sum[l]);
else dp[i][now] = sum[i];
while(p+2 <= i && dp[p+1][now^1] + sum[p+2] <= sum[i]) p += 2;
if(l < p) dp[i][now] = min(dp[i][now], sum[i] - sum[p]);
if(!(i&1)) { while(s <= t && dp[q[t]-1][now^1] >= dp[i-1][now^1]) --t; q[++t] = i; }
while(s <= t && q[s] <= p) ++s;
if(s <= t) dp[i][now] = min(dp[q[s]-1][now^1], dp[i][now]);
}
ans = max(ans, (all + (n-1-j)*K - j) - dp[N][now]);
}
printf("%d\n", ans);
}