给定序列
emm 第一眼想到的是
后者整理得:
前者二维偏序可以优化到
Upd:也可以强行优化,发现
xxxxxxxxxx89123
4567891011
12using namespace std;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
2324
25template < typename T = int >26inline T read(void);27
28int N;29
30namespace Sub_1_2{31 ll A[5100];32 ll dp[5100][5100];33 void Make(void){34 memset(dp, 0xc0, sizeof dp);35 for(int i = 1; i <= N; ++i)A[i] = read();36 A[0] = -INF;37 dp[1][0] = A[1], dp[1][1] = -1;38 for(int i = 2; i <= N; ++i){39 for(int j = 0; j <= i - 1; ++j)40 if(A[i] >= A[i - 1 - j])41 dp[i][0] = max(dp[i][0], dp[i - 1][j] + A[i]);42 for(int j = 1; j <= i; ++j)43 dp[i][j] = dp[i - 1][j - 1] + (((j - 1) * j) >> 1) - ((j * (j + 1)) >> 1);44 }45 ll ans(-INF);46 for(int j = 0; j <= N; ++j)ans = max(ans, dp[N][j]);47 printf("%lld\n", ans);48 }49}50namespace Sub_3_4{51 ll A[1100000];52 void Make(void){53 for(int i = 1; i <= N; ++i)A[i] = read();54
55 }56}57int main(){58 freopen("paint.in", "r", stdin);59 freopen("paint.out", "w", stdout);60 N = read();61 if(N <= 10000)Sub_1_2::Make();62 else exit(1);63 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);64 return 0;65}66
67/*687691 3 2 7 3 2 470
71772-3 -4 -2 -2 -6 -8 -173*/74
75template < typename T >76inline T read(void){77 T ret(0);78 int flag(1);79 char c = getchar();80 while(c != '-' && !isdigit(c))c = getchar();81 if(c == '-')flag = -1, c = getchar();82 while(isdigit(c)){83 ret *= 10;84 ret += int(c - '0');85 c = getchar();86 }87 ret *= flag;88 return ret;89}给定字符串
基于 LG-P4324 [JSOI2016]扭动的回文串 修改的。
赛时一看默认这是 PAM 之类的东西(犇犇 @sssmzy 真的写了个 PAM)于是就跳了,写了个
正解真的巨简单
xxxxxxxxxx93123
4567891011
12using namespace std;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
2324
25template < typename T = int >26inline T read(void);27
28int N;29string S;30
31namespace Sub_1_2{32 int ans(0);33 unll pow_base[210];34 unll hash[210], rhash[210];35 void Cal(void){36 hash[0] = rhash[N + 1] = 0;37 for(int i = 1; i <= N; ++i)hash[i] = hash[i - 1] * BASE + S.at(i - 1);38 for(int i = N; i >= 1; --i)rhash[i] = rhash[i + 1] * BASE + S.at(i - 1);39 for(int l = 1; l <= N; ++l){40 for(int r = l; r <= N; ++r){41 unll hash1 = hash[r] - hash[l - 1] * pow_base[r - l + 1];42 unll hash2 = rhash[l] - rhash[r + 1] * pow_base[r - l + 1];43 if(hash1 == hash2)ans = max(ans, r - l + 1);44 }45 }46 }47 void Make(void){48 pow_base[0] = 1;49 for(int i = 1; i <= 205; ++i)pow_base[i] = pow_base[i - 1] * BASE;50 Cal();51 for(int i = 1; i <= N - 2; ++i){52 char c = getchar(); while(!isalpha(c))c = getchar();53 S.at(i) = c;54 Cal();55 }printf("%d\n", ans);56 }57}58
59
60int main(){61 freopen("str.in", "r", stdin);62 freopen("str.out", "w", stdout);63 N = read(); cin >> S;64 if(N <= 600)Sub_1_2::Make();65 else puts("qwq");66 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);67 return 0;68}69
70/*71672ABAECB73B74C75D76E77*/78
79template < typename T >80inline T read(void){81 T ret(0);82 int flag(1);83 char c = getchar();84 while(c != '-' && !isdigit(c))c = getchar();85 if(c == '-')flag = -1, c = getchar();86 while(isdigit(c)){87 ret *= 10;88 ret += int(c - '0');89 c = getchar();90 }91 ret *= flag;92 return ret;93}还算是相对比较接近切掉的一道题。
给定序列
求操作
Tips:序列下标从
手画一下,例如
xxxxxxxxxx173123
4567891011
12using namespace std;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
23242526
27template < typename T = int >28inline T read(void);29
30int N, K; ll T;31int pos[410000];32ll g(3), inv_g;33ll A[410000];34
35ll qpow(ll a, ll b){36 ll ret(1), mul(a);37 while(b){38 if(b & 1)ret = ret * mul % MOD;39 b >>= 1;40 mul = mul * mul % MOD;41 }return ret;42}43
44class Polynomial{45private:46public:47 int len;48 ll poly[410000];49 Polynomial(void){50 len = 0;51 memset(poly, 0, sizeof poly);52 }53 void Reverse(void){54 for(int i = 0; i < len; ++i)55 pos[i] = (pos[i >> 1] >> 1) | (i & 1 ? len >> 1 : 0);56 for(int i = 0; i < len; ++i)if(i < pos[i])swap(poly[i], poly[pos[i]]);57 }58 void Shrink(void){59 for(int i = N; i < len; ++i)(poly[i % N] += poly[i]) %= MOD, poly[i] = 0;60 for(int i = 0; i < len; ++i)poly[i] %= 2;61 len = min(len, N);62 }63 void NTT(bool pat){64 Reverse();65 for(int siz = 2; siz <= len; siz <<= 1){66 ll gn = qpow(pat ? g : inv_g, (MOD - 1) / siz);67 for(auto p = poly; p != poly + len; p += siz){68 int mid = siz >> 1; ll g(1);69 for(int i = 0; i < mid; ++i, (g *= gn) %= MOD){70 auto tmp = g * p[i + mid] % MOD;71 p[i + mid] = (p[i] - tmp + MOD) % MOD;72 p[i] = (p[i] + tmp) % MOD;73 }74 }75 }76 if(!pat){77 ll inv_len = qpow(len, MOD - 2);78 for(int i = 0; i < len; ++i)(poly[i] *= inv_len) %= MOD;79 Shrink();80 }81 }82 void Print(void){83 printf("Polynomial(len = %d): ", len);84 for(int i = 0; i < len; ++i)printf("%lld ", poly[i]);85 printf("\n");86 }87};88
89Polynomial ret, mul;90void qpow(Polynomial* a, ll b){91 for(int i = 0; i < ret.len; ++i)ret.poly[i] = 0;92 ret.len = 1, ret.poly[0] = 1;93 mul = *a;94 while(b){95 if(b & 1){96 int base(1); while(base < ret.len + mul.len - 1)base <<= 1;97 ret.len = mul.len = base;98 ret.NTT(DFT), mul.NTT(DFT);99 for(int i = 0; i < base; ++i)ret.poly[i] = ret.poly[i] * mul.poly[i] % MOD;100 ret.NTT(IDFT), mul.NTT(IDFT);101 }102 b >>= 1;103 int base(1); while(base < mul.len + mul.len - 1)base <<= 1;104 mul.len = base;105 mul.NTT(DFT);106 for(int i = 0; i < base; ++i)mul.poly[i] = mul.poly[i] * mul.poly[i] % MOD;107 mul.NTT(IDFT);108 }109}110
111
112int main(){113 freopen("xortwo.in", "r", stdin);114 freopen("xortwo.out", "w", stdout);115 inv_g = qpow(g, MOD - 2);116 N = read(), K = read(); T = read < ll >();117 Polynomial origin;118 origin.len = K;119 for(int i = 0; i < origin.len; ++i)origin.poly[i] = 1;120 // {121 // int base(1); while(base < origin.len)base <<= 1;122 // origin.len = base;123 // origin.Print();124 // origin.NTT(DFT), origin.NTT(IDFT);125 // origin.Print();126 // base = (1); while(base < origin.len)base <<= 1;127 // origin.len = base;128 // origin.NTT(DFT), origin.NTT(IDFT);129 // origin.Print();130 // }131 qpow(&origin, T);132 basic_string < int > isTrue;133 for(int i = 0; i < N; ++i)if(ret.poly[i])isTrue += i;134 // ret.Print();135 for(int i = 0; i < N; ++i)A[i] = read();136 for(int i = 0; i < N; ++i){137 ll val(0);138 for(auto j : isTrue)val ^= A[(i + j) % N];139 printf("%lld%c", val, i == N - 1 ? '\n' : ' ');140 }141 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);142 return 0;143}144
145/*1465 3 11473 0 2 1 2148
1495 3 21503 0 2 1 2151
1525 3 151533 0 2 1 2154
15511 5 10000000000000000001562 2 4 5 9 1 5 7 7 1 8157*/158
159template < typename T >160inline T read(void){161 T ret(0);162 int flag(1);163 char c = getchar();164 while(c != '-' && !isdigit(c))c = getchar();165 if(c == '-')flag = -1, c = getchar();166 while(isdigit(c)){167 ret *= 10;168 ret += int(c - '0');169 c = getchar();170 }171 ret *= flag;172 return ret;173}简单设一个
就是个哈希,类比一下原题就行,分割成中间的回文串和左右相同的两串,中间回文串满足单调性,跑一下即可。
另外对于一般的哈希也是满足单调性的,枚举每一个中点然后取最大值并令其不降最终就是
考虑最终将二进制拆位并 NTT 即可,此时就能几乎拿满了。对于过程中会发现有一些难以想到的性质,emm 大概就是能推成一个新的柿子,然后就能优化,emmmmmm 这个东西吧。。反正很奇怪就对了。
代码实现就先都咕着了。
update-2023_02_04 初稿