给定序列
emm 第一眼想到的是
后者整理得:
前者二维偏序可以优化到
Upd:也可以强行优化,发现
xxxxxxxxxx
891
2
3
4
5
6
7
8
9
10
11
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
23
24
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/*
687
691 3 2 7 3 2 4
70
717
72-3 -4 -2 -2 -6 -8 -1
73*/
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)于是就跳了,写了个
正解真的巨简单
xxxxxxxxxx
931
2
3
4
5
6
7
8
9
10
11
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
23
24
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/*
716
72ABAECB
73B
74C
75D
76E
77*/
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:序列下标从
手画一下,例如
xxxxxxxxxx
1731
2
3
4
5
6
7
8
9
10
11
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
23
24
25
26
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 1
1473 0 2 1 2
148
1495 3 2
1503 0 2 1 2
151
1525 3 15
1533 0 2 1 2
154
15511 5 1000000000000000000
1562 2 4 5 9 1 5 7 7 1 8
157*/
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 初稿