杂题小记(2023.02.25)更好的阅读体验戳此进入PJudge-21739 A. 【NOIP Round #5】青鱼和序列题面SolutionCodePjudge-21743 B. 【NOIP Round #5】青鱼和怪兽题面SolutionCodeLG-P4097 [HEOI2013]Segment题面SolutionCodeLG-P5249 [LnOI2019]加特林轮盘赌题面SolutionCodeUPD
给定初始序列,存在两种操作,将序列复制并接在前面,将序列复制并翻转并接在前面,需要在
“容易” 发现翻转多次与翻转一次等效,“容易” 发现一次的翻转在任意位置都等效,于是模拟跑一下即可。
复杂度最优可以优化到
xxxxxxxxxx
911
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, M;
29ll A[110000];
30ll sum[110000], rsum[110000], ssum, srsum;
31ll pow2s[110000], pow2[110000];
32ll spow2s[110000];
33
34int main(){
35 N = read(), M = read();
36 for(int i = 1; i <= N; ++i)A[i] = read();
37 for(int i = 1; i <= N; ++i)sum[i] = (sum[i - 1] + A[i]) % MOD;
38 for(int i = N; i >= 1; --i)rsum[i] = (rsum[i + 1] + A[i]) % MOD;
39 for(int i = 1; i <= N; ++i)(ssum += sum[i]) %= MOD, (srsum += rsum[i]) %= MOD;
40 ll base(N);
41 for(int i = 1; i <= M - 1; ++i){
42 ssum = (ssum + ssum + sum[N] * base % MOD) % MOD;
43 srsum = (srsum + srsum + sum[N] * base % MOD) % MOD;
44 (sum[N] *= 2) %= MOD;
45 (base <<= 1) %= MOD;
46 }
47 printf("%lld\n", max((ssum + ssum + sum[N] * base % MOD) % MOD, (ssum + srsum + sum[N] * base % MOD) % MOD));
48 // pow2s[0] = sum[N] * N % MOD, pow2[0] = 1;
49 // for(int i = 1; i <= M; ++i)pow2s[i] = pow2s[i - 1] * 4 % MOD, pow2[i] = pow2[i - 1] * 2 % MOD;
50 // for(int i = 0; i <= M; ++i)spow2s[i] = ((i - 1 >= 0 ? spow2s[i - 1] : 0) + pow2s[i]) % MOD;
51 // ll ans((ssum * pow2[M] % MOD + spow2s[M - 1]) % MOD);
52 // ssum = (ssum * pow2[M - 1] % MOD + (M - 2 >= 0 ? spow2s[M - 2] : 0)) % MOD;
53 // srsum = (srsum * pow2[M - 1] % MOD + (M - 2 >= 0 ? spow2s[M - 2] : 0)) % MOD;
54 // ll tmp = ssum;
55 // ssum = ((ssum + srsum) % MOD + pow2s[M - 1]) % MOD;
56 // ans = max(ans, ssum);
57 // //unreverse todo
58 // ll origin_ssum = ssum, origin_srsum = srsum;
59 // for(int rev = 1; rev <= M; ++rev){
60 // ssum = origin_ssum, srsum = origin_srsum;
61 // int d = rev - 1;
62 // ssum = (ssum * pow2[d] % MOD + (rev - 2 >= 0 ? spow2s[rev - 1] : 0)) % MOD;
63 // srsum = (srsum * pow2[d] % MOD + (rev - 2 >= 0 ? spow2s[rev - 1] : 0)) % MOD;
64 // ll tmp = ssum;
65 // (ssum += (srsum + pow2s[rev]) % MOD) %= MOD;
66 // (srsum += (tmp + pow2s[rev]) % MOD) %= MOD;
67 // d = M - rev;
68 // ssum = (ssum * pow2[d] % MOD + (spow2s[M] - spow2s[rev] + MOD) % MOD) % MOD;
69 // ans = max(ans, ssum);
70 // printf("rev = %d, ssum = %lld\n", rev, ssum);
71 // }
72 // printf("%lld\n", ans);
73 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
74 return 0;
75}
76
77template < typename T >
78inline T read(void){
79 T ret(0);
80 int flag(1);
81 char c = getchar();
82 while(c != '-' && !isdigit(c))c = getchar();
83 if(c == '-')flag = -1, c = getchar();
84 while(isdigit(c)){
85 ret *= 10;
86 ret += int(c - '0');
87 c = getchar();
88 }
89 ret *= flag;
90 return ret;
91}
存在怪兽,你有
考虑一个朴素的 DP,令
xxxxxxxxxx
731
2
3
4
5
6
7
8
9
10
11
12
13using namespace std;
14
15mt19937 rnd(random_device{}());
16int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
17bool rnddd(int x){return rndd(1, 100) <= x;}
18
19typedef unsigned int uint;
20typedef unsigned long long unll;
21typedef long long ll;
22typedef long double ld;
23
24
25
26template < typename T = int >
27inline T read(void);
28
29int N, M, C;
30ld P;
31ld dp[1100][1100];
32
33bool Check(ld tim){
34 for(int i = 0; i <= N + 10; ++i)
35 dp[i][0] = 0.0;
36 for(int j = 0; j <= M + 10; ++j)
37 dp[0][j] = tim;
38 for(int i = 1; i <= N; ++i)
39 for(int j = 1; j <= M; ++j)
40 dp[i][j] = min(tim, (dp[i - 1][j] + 1) * (1.0 - P) + (dp[i][j - 1] + 1) * P);
41 return dp[N][M] < tim;
42}
43
44int main(){
45 N = read(), M = read(), C = read();
46 P = (ld)C / 100.0;
47 ld l = EPS, r = 1e9, ans(-1.0);
48 while(fabs(l - r) > EPS){
49 ld mid = (l + r) / 2.0;
50 ans = mid;
51 if(Check(mid))r = mid - EPS;
52 else l = mid + EPS;
53 }printf("%.8Lf\n", ans);
54
55 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
56 return 0;
57}
58
59template < typename T >
60inline T read(void){
61 T ret(0);
62 int flag(1);
63 char c = getchar();
64 while(c != '-' && !isdigit(c))c = getchar();
65 if(c == '-')flag = -1, c = getchar();
66 while(isdigit(c)){
67 ret *= 10;
68 ret += int(c - '0');
69 c = getchar();
70 }
71 ret *= flag;
72 return ret;
73}
插线段,求点对应最大值且序号最小的线段。
李超线段树模板解决。
xxxxxxxxxx
1151
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
26template < typename T = int >
27inline T read(void);
28
29struct Interval{
30 bool flag;
31 int idx;
32 double k, b;
33 double CalVal(int x){
34 return k * x + b;
35 }
36};
37class LCSegTree{
38private:
39 Interval tr[LIM << 2];
40
41
42
43public:
44 void Update(Interval line, int p, int gl, int gr){
45 if(!tr[p].flag)return tr[p] = line, void();
46 if(fabs(line.CalVal(MID) - tr[p].CalVal(MID)) < EPS){
47 if(line.idx < tr[p].idx)swap(tr[p], line);
48 }else if(line.CalVal(MID) > tr[p].CalVal(MID))swap(tr[p], line);
49 if(gl != gr && (fabs(line.CalVal(gl) - tr[p].CalVal(gl)) < EPS || line.CalVal(gl) > tr[p].CalVal(gl)))Update(line, LS, gl, MID);
50 if(gl != gr && (fabs(line.CalVal(gr) - tr[p].CalVal(gr)) < EPS || line.CalVal(gr) > tr[p].CalVal(gr)))Update(line, RS, MID + 1, gr);
51 }
52 void UpdatePoint(int pos, int val, int idx, int p = 1, int gl = 1, int gr = LIM){
53 if(gl == gr){
54 if(!tr[p].flag)tr[p] = Interval{true, idx, 0.0, (double)val};
55 else if(fabs(tr[p].CalVal(pos) - (double)val) < EPS)tr[p].idx = min(tr[p].idx, idx);
56 else if(tr[p].CalVal(pos) < (double)val)tr[p] = Interval{true, idx, 0.0, (double)val};
57 return;
58 }
59 if(pos <= MID)UpdatePoint(pos, val, idx, LS, gl, MID);
60 else UpdatePoint(pos, val, idx, RS, MID + 1, gr);
61 }
62 void Insert(Interval line, int l, int r, int p = 1, int gl = 1, int gr = LIM){
63 if(l <= gl && gr <= r)return Update(line, p, gl, gr);
64 if(l <= MID)Insert(line, l, r, LS, gl, MID);
65 if(r >= MID + 1)Insert(line, l, r, RS, MID + 1, gr);
66 }
67 pair < int, double > Query(int pos, int p = 1, int gl = 1, int gr = LIM){
68 auto ret = tr[p].idx; auto mxv = tr[p].CalVal(pos);
69 if(gl != gr){
70 auto vals = pos <= MID ? Query(pos, LS, gl, MID) : Query(pos, RS, MID + 1, gr);
71 if(fabs(vals.second - mxv) < EPS)ret = min(ret, vals.first);
72 else if(vals.second > mxv)ret = vals.first, mxv = vals.second;
73 }return {ret, mxv};
74 }
75}lcst;
76
77int N;
78int cnt(0);
79int lst(0);
80
81int main(){
82 N = read();
83 for(int i = 1; i <= N; ++i){
84 int opt = read();
85 if(opt == 0){
86 int ans = lcst.Query((read() + lst - 1) % 39989 + 1).first;
87 lst = ans;
88 printf("%d\n", ans);
89 continue;
90 }
91 int sx = (read() + lst - 1) % 39989 + 1, sy = (read() + lst - 1) % (int)(1e9) + 1;
92 int tx = (read() + lst - 1) % 39989 + 1, ty = (read() + lst - 1) % (int)(1e9) + 1;
93 if(sx == tx)lcst.UpdatePoint(sx = tx, max(sy, ty), ++cnt);
94 else lcst.Insert(Interval{true, ++cnt, (double)(ty - sy) / (tx - sx), (double)ty - (double)(ty - sy) / (tx - sx) * tx}, min(sx, tx), max(sx, tx));
95 }
96
97 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
98 return 0;
99}
100
101template < typename T >
102inline T read(void){
103 T ret(0);
104 int flag(1);
105 char c = getchar();
106 while(c != '-' && !isdigit(c))c = getchar();
107 if(c == '-')flag = -1, c = getchar();
108 while(isdigit(c)){
109 ret *= 10;
110 ret += int(c - '0');
111 c = getchar();
112 }
113 ret *= flag;
114 return ret;
115}
存在加特林,存在
很有意思的一道题,和一般的朴素概率 DP 不尽相同。
前面的思路和其它题解差不多,主要细说一下最后推式子的步骤。
对于
也就是说考虑其原本处于第
写到这就不难发现这东西是存在后效性的,或者说不存在初值,但是仍然存在显然的
于是考虑扩展到
此时我们仔细想一下刚才的过程,不难发现意义就是我们每次只崩首位的人,崩完之后不移动枪,而是将整个圆排列对应旋转。
然后我们考虑对于中间的转移,不难想到对于
当然我们这东西是没有初值的,不能直接递推,但是共存在
考虑对于
令
这样我们可以用
注意需要特判
最终时间复杂度
xxxxxxxxxx
651
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
28ld P;
29int N, K;
30ld dp[2][11000];
31
32int main(){
33 scanf("%Lf", &P), N = read(), K = read();
34 if(P < EPS)printf("%.10Lf\n", N == 1 ? (ld)1 : (ld)0), exit(0);
35 dp[1][1] = 1.0;
36 bool cur(false);
37 for(int i = 2; i <= N; ++i){
38 ld K(1.0), B(0.0), base1(1.0), base2(0.0);
39 for(int j = 2; j <= i; ++j)
40 base1 *= (1 - P), base2 = base2 * (1 - P) + P * dp[cur ^ 1][j - 1],
41 K += base1, B += base2;
42 dp[cur][1] = (1 - B) / K;
43 for(int j = 2; j <= i; ++j)
44 dp[cur][j] = (1 - P) * dp[cur][j - 1] + P * dp[cur ^ 1][j - 1];
45 cur ^= 1;
46 }printf("%.10Lf\n", dp[cur ^ 1][K]);
47 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
48 return 0;
49}
50
51template < typename T >
52inline T read(void){
53 T ret(0);
54 int flag(1);
55 char c = getchar();
56 while(c != '-' && !isdigit(c))c = getchar();
57 if(c == '-')flag = -1, c = getchar();
58 while(isdigit(c)){
59 ret *= 10;
60 ret += int(c - '0');
61 c = getchar();
62 }
63 ret *= flag;
64 return ret;
65}
update-2023_02_25 初稿