给定
类似的原题是 Vijos-1065 最小数字倍数,该题要求仅存在对应数。
一道很简单但做得很麻烦的题,首先考虑的是
转移及其复杂,需要考虑很多细节,也不知道我咋想出来的,奇奇怪怪。
xxxxxxxxxx
1331
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/*
2437 9
250 1 2 3 4 5 6 7 9
26
27233333 8
282 3 4 5 6 7 8 9
29*/
30
31template < typename T = int >
32inline T read(void);
33
34bitset < 10 > exist[20];
35
36bitset < 10 > ban;
37
38int K, T;
39
40// basic_string < int > ends[10];
41map < int, int > mp;
42unordered_set < int > vis;
43unordered_set < int > nums;
44unordered_set < int > legal;
45ll dp[20][1100000];
46ll pow10[20];
47ll ans(LONG_LONG_MAX);
48
49int main(){
50 freopen("digit.in", "r", stdin);
51 freopen("digit.out", "w", stdout);
52 pow10[0] = 1;
53 for(int i = 1; i <= 18; ++i)pow10[i] = pow10[i - 1] * 10;
54 memset(dp, -1, sizeof dp);
55 K = read(), T = read();
56 int digitK(0), tmp = K;
57 while(tmp)++digitK, tmp /= 10;
58 for(int i = 1; i <= T; ++i)ban[read()] = true;
59 if(K == 0)printf("%d\n", ban[0] ? -1 : 0), exit(0);
60 for(int i = 1; i <= 2 * K; ++i){
61 int val = i;
62 bool flag(true);
63 while(val){
64 if(ban[val % 10]){flag = false; break;}
65 val /= 10;
66 }if(flag)legal.insert(i);
67 }
68 for(int j = 1; vis.find(K * j % 10) == vis.end(); ++j){
69 vis.insert(K * j % 10);
70 // if(!ban[K * j % 10])nums.insert(K * j % 10), mp[K * j % 10] = K * j;
71 nums.insert(K * j % 10), mp[K * j % 10] = K * j;
72 }
73 // dp[0][0][0] = 0;
74 for(auto num : nums){
75 if(ban[mp[num] % 10])continue;
76 dp[1][mp[num] / 10] = mp[num];
77 // printf("upd dp[%d][%d] = %d\n", 1, mp[num] / 10, mp[num]);
78 if(!(mp[num] / 10) || legal.find(mp[num] / 10) != legal.end())ans = min(ans, dp[1][mp[num] / 10]);
79 }if(ans != LONG_LONG_MAX)printf("%lld\n", ans), exit(0);
80 // exit(0);
81 for(int i = 1; i <= 18 - digitK; ++i){
82 for(auto j : nums){
83 for(int k = 0; k <= 1000000; ++k){
84 if(!~dp[i][k])continue;
85 if(ban[(j + k % 10) % 10])continue;
86 if(j + k % 10 <= 9){
87 // printf("[%d][%d][%d] => [%d][%d][%d]\n", i, j, k, i + 1, j + k % 10, k / 10 + mp[j] / 10);
88 dp[i + 1][k / 10 + mp[j] / 10] = dp[i][k] + (ll)mp[j] * pow10[i];
89 if(!(k / 10 + mp[j] / 10) || legal.find(k / 10 + mp[j] / 10) != legal.end())ans = min(ans, dp[i + 1][k / 10 + mp[j] / 10]);
90 }else{
91 // printf("[%d][%d][%d] => [%d][%d][%d]\n", i, j, k, i + 1, (j + k % 10) % 10, k / 10 + mp[j] / 10 + 1);
92 dp[i + 1][k / 10 + mp[j] / 10 + 1] = dp[i][k] + (ll)mp[j] * pow10[i];
93 if(!(k / 10 + mp[j] / 10 + 1) || legal.find(k / 10 + mp[j] / 10 + 1) != legal.end())ans = min(ans, dp[i + 1][k / 10 + mp[j] / 10 + 1]);
94 }
95 }
96 }
97 if(ans != LONG_LONG_MAX)printf("%lld\n", ans), exit(0);
98 }printf("-1\n");
99
100 // int N = read();
101 // for(int i = 1; i <= 10000; ++i){
102 // ll val = (ll)N * i;
103 // int cnt(0);
104 // while(val){
105 // exist[++cnt][val % 10] = true;
106 // val /= 10;
107 // }
108 // }
109 // for(int i = 1; i <= 10; ++i){
110 // printf("digit %d : ", i);
111 // for(int j = 0; j <= 9; ++j)if(exist[i][j])printf("%d ", j);
112 // printf("\n");
113 // }
114
115 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
116 return 0;
117}
118
119template < typename T >
120inline T read(void){
121 T ret(0);
122 int flag(1);
123 char c = getchar();
124 while(c != '-' && !isdigit(c))c = getchar();
125 if(c == '-')flag = -1, c = getchar();
126 while(isdigit(c)){
127 ret *= 10;
128 ret += int(c - '0');
129 c = getchar();
130 }
131 ret *= flag;
132 return ret;
133}
存在
大概想出来贪心了,左端点排序然后右端点排序建堆,但是取元素然后区间覆盖的时候一直没太想好怎么处理,主要的问题是卡在了,建树最大实际上应该是
xxxxxxxxxx
1331
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/*
253
265
271 4 2
283 6 3
294 5 2
304 7 2
315 8 1
326
331 7 25
344 8 10
357 10 5
368 11 5
3710 13 10
3811 13 5
398
4015 18 10
4120 24 16
428 15 33
4311 14 14
441 6 16
4516 19 12
463 5 12
4722 25 10
48*/
49
50template < typename T = int >
51inline T read(void);
52
53int N;
54
55struct Task{
56 ld s, t;
57 ld w;
58 friend const bool operator < (const Task &a, const Task &b){
59 return a.t > b.t;
60 }
61}task[21000];
62
63// class SegTree{
64// private:
65// int tr[21000000 << 2], lz[]
66// public:
67// void Pushup(int p){
68
69// }
70// }
71
72bool Check(int V){
73 int curpos(1);
74 priority_queue < Task > tsk;
75 ld curT(1.0);
76 while(true){
77 if(tsk.empty()){
78 if(curpos > N)return true;
79 curT = max(curT, (ld)task[curpos].s);
80 while(curpos <= N && curT >= (ld)task[curpos].s)tsk.push(task[curpos++]);
81 }
82
83 auto tp = tsk.top(); tsk.pop();
84 curT = max(curT, (ld)tp.s);
85 auto nxt = tsk.empty() ? Task{INT_MAX, INT_MAX, INT_MAX} : tsk.top();
86 if(curT + (ld)tp.w / (ld)V <= nxt.s){
87 curT += (ld)tp.w / (ld)V;
88 if(curT - EPS > (ld)tp.t)return false;
89 }else{
90 tsk.push(Task{nxt.s, tp.t, tp.w - (nxt.s - curT) * V});
91 curT = nxt.s;
92 }
93
94 // printf("V = %d, curT = %.5Lf, [%d ~ %d]\n", V, curT, tp.s, tp.t);
95
96 while(curpos <= N && curT >= (ld)task[curpos].s)tsk.push(task[curpos++]);
97 }
98}
99
100int main(){
101 freopen("cpu.in", "r", stdin);
102 freopen("cpu.out", "w", stdout);
103 int T = read();
104 while(T--){
105 N = read();
106 for(int i = 1; i <= N; ++i)task[i].s = read(), task[i].t = read(), task[i].w = read();
107 sort(task + 1, task + N + 1, [](const Task &a, const Task &b)->bool{return a.s < b.s;});
108 int l = 0, r = 21000000, ans(-1);
109 while(l <= r){
110 int mid = (l + r) >> 1;
111 if(Check(mid))ans = mid, r = mid - 1;
112 else l = mid + 1;
113 }printf("%d\n", ans);
114 }
115 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
116 return 0;
117}
118
119template < typename T >
120inline T read(void){
121 T ret(0);
122 int flag(1);
123 char c = getchar();
124 while(c != '-' && !isdigit(c))c = getchar();
125 if(c == '-')flag = -1, c = getchar();
126 while(isdigit(c)){
127 ret *= 10;
128 ret += int(c - '0');
129 c = getchar();
130 }
131 ret *= flag;
132 return ret;
133}
存在初始全为白色的序列,每次从
手推了一下次数为
xxxxxxxxxx
921
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
28ll N, K;
29
30ll qpow(ll a, ll b){
31 ll ret(1), mul(a);
32 while(b){
33 if(b & 1)ret = ret * mul % MOD;
34 b >>= 1;
35 mul = mul * mul % MOD;
36 }return ret;
37}
38
39ll dp[20][20][20];
40ll ans(0);
41
42int main(){
43 freopen("paint.in", "r", stdin);
44 freopen("paint.out", "w", stdout);
45 // printf("%lld\n", 17 * qpow(9, MOD - 2) % MOD);
46 N = read(), K = read();
47 if(K == 1){
48 // ll v = (N + 2) >> 1;
49 // printf("%lld\n", ((v * ((2 * N + 2) % MOD) % MOD - v * (v + 1) % MOD + (N - v) * ((2 * N + 2) % MOD) % MOD - (N + v + 1) % MOD * (N - v) % MOD) % MOD + MOD) % MOD * qpow(N, MOD - 2) % MOD * qpow(N, MOD - 2) % MOD);
50 printf("%lld\n", (((N + 1) * (N + 1) % MOD * N % MOD - N * (N + 1) % MOD * ((2 * N + 1) % MOD) % MOD * qpow(3, MOD - 2) % MOD - N) % MOD + MOD) % MOD * qpow(N, MOD - 2) % MOD * qpow(N, MOD - 2) % MOD);
51 exit(0);
52 }
53 ll base = qpow(N, MOD - 2) * qpow(N, MOD - 2) % MOD;
54 for(int i = 1; i <= N; ++i)
55 for(int j = 1; j <= N; ++j)
56 (dp[1][min(i, j)][max(i, j)] += base) %= MOD;
57 for(int i = 2; i <= K; ++i){
58 for(int j = 1; j <= N; ++j){
59 for(int k = 1; k <= N; ++k){
60 int l = min(j, k), r = max(j, k);
61 for(int L = 1; L <= N; ++L){
62 for(int R = L; R <= N; ++R){
63 int rl = min(l, L), rr = max(r, R);
64 (dp[i][rl][rr] += dp[i - 1][L][R] * base % MOD) %= MOD;
65 }
66 }
67 }
68 }
69 }
70 for(int i = 1; i <= N; ++i)
71 for(int j = i; j <= N; ++j)
72 (ans += dp[K][i][j] * (j - i + 1) % MOD) %= MOD;
73 printf("%lld\n", ans);
74 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
75 return 0;
76}
77
78template < typename T >
79inline T read(void){
80 T ret(0);
81 int flag(1);
82 char c = getchar();
83 while(c != '-' && !isdigit(c))c = getchar();
84 if(c == '-')flag = -1, c = getchar();
85 while(isdigit(c)){
86 ret *= 10;
87 ret += int(c - '0');
88 c = getchar();
89 }
90 ret *= flag;
91 return ret;
92}
给定序列
xxxxxxxxxx
971
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/*
245 4
251 5 3 3 1
263 3 4
274 4 5
282 1 4
295 3 5
30*/
31
32template < typename T = int >
33inline T read(void);
34
35int N, Q;
36int A[210000];
37basic_string < int > pos[1100];
38
39// class SegTree{
40// private:
41// int tr[210000 << 2];
42// #define LS (p << 1)
43// #define RS (LS | 1)
44// #define MID ((gl + gr) >> 1)
45// public:
46// void Pushup()
47// }
48
49int main(){
50 freopen("magic.in", "r", stdin);
51 freopen("magic.out", "w", stdout);
52 N = read(), Q = read();
53 for(int i = 1; i <= N; ++i)pos[A[i] = read()] += i;
54 if(N > 5000){
55 while(Q--){
56 ll ans(0);
57 int p = read(), l = read(), r = read();
58 r = min(r, N);
59 if(p < l)ans = (ll)(l - p + r - p) * (r - p - (l - p) + 1) / 2;
60 else if(p > r)ans = (ll)(p - l + p - r) * (p - l - (p - r) + 1) / 2;
61 else ans = (ll)(p - l + 1) * (p - l) / 2 + (ll)(r - p + 1) * (r - p) / 2;
62 printf("%lld\n", ans);
63 }
64 }
65 while(Q--){
66 ll ans(0);
67 int p = read(), l = read(), r = read();
68 for(int i = l; i <= r; ++i){
69 if(pos[i].empty())continue;
70 int mn(INT_MAX);
71 auto it = lower_bound(pos[i].begin(), pos[i].end(), p);
72 if(it != pos[i].end())mn = min(mn, abs(p - *it));
73 if(it != pos[i].begin())mn = min(mn, abs(p - *prev(it)));
74 if(it != pos[i].end() && next(it) != pos[i].end())mn = min(mn, abs(p - *next(it)));
75 ans += mn;
76 }printf("%lld\n", ans);
77 }
78
79 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
80 return 0;
81}
82
83template < typename T >
84inline T read(void){
85 T ret(0);
86 int flag(1);
87 char c = getchar();
88 while(c != '-' && !isdigit(c))c = getchar();
89 if(c == '-')flag = -1, c = getchar();
90 while(isdigit(c)){
91 ret *= 10;
92 ret += int(c - '0');
93 c = getchar();
94 }
95 ret *= flag;
96 return ret;
97}
考虑
还有更平凡的做法即进行 bfs,记录前驱以及具体数位值,跑一遍即可。
xxxxxxxxxx
851
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 K, T;
29bitset < 10 > ban;
30basic_string < int > vals;
31bitset < 1100000 > vis;
32
33struct Node{
34 int p; int val; Node* pre;
35};
36void Print(Node* p){
37 basic_string < int > ans;
38 for(auto cur = p; ~cur->val; cur = cur->pre)
39 ans += cur->val;
40 reverse(ans.begin(), ans.end());
41 for(auto v : ans)printf("%d", v);
42 printf("\n");
43 exit(0);
44}
45void bfs(void){
46 queue < Node* > cur;
47 cur.push(new Node{0, -1, npt});
48 while(!cur.empty()){
49 auto p = cur.front(); cur.pop();
50 for(auto i : vals){
51 if(p->p == 0 && i == 0)continue;
52 int np = (p->p * 10 + i) % K;
53 auto nod = new Node{np, i, p};
54 if(!np)return Print(nod);
55 if(vis[np])continue;
56 vis[np] = true;
57 cur.push(nod);
58 }
59 }
60}
61
62int main(){
63 K = read(), T = read();
64 for(int i = 1; i <= T; ++i)vals += read();
65 bfs();
66 printf("-1\n");
67 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
68 return 0;
69}
70
71template < typename T >
72inline T read(void){
73 T ret(0);
74 int flag(1);
75 char c = getchar();
76 while(c != '-' && !isdigit(c))c = getchar();
77 if(c == '-')flag = -1, c = getchar();
78 while(isdigit(c)){
79 ret *= 10;
80 ret += int(c - '0');
81 c = getchar();
82 }
83 ret *= flag;
84 return ret;
85}
问题关键在于转换,即不去枚举事件,而去枚举时间,这样贪心更显然且极好维护。
xxxxxxxxxx
871
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
23template < typename T = int >
24inline T read(void);
25
26int N;
27
28struct Task{
29 int s, t;
30 int w;
31 friend const bool operator < (const Task &a, const Task &b){
32 return a.t > b.t;
33 }
34}task[21000];
35
36bool Check(int V){
37 int curpos(1);
38 priority_queue < Task > tsk;
39 for(int i = 1; i <= 20000; ++i){
40 while(curpos <= N && i >= task[curpos].s)tsk.push(task[curpos++]);
41 int tot(V);
42 while(!tsk.empty() && tot){
43 if(i >= tsk.top().t)return false;
44 // printf("i = %d, Making [%d, %d]\n", )
45 if(tot >= tsk.top().w)tot -= tsk.top().w, tsk.pop();
46 else{
47 auto tp = tsk.top(); tsk.pop();
48 tp.w -= tot; tot = 0; tsk.push(tp);
49 break;
50 }
51 }
52 }if(curpos <= N || !tsk.empty())return false;
53 return true;
54}
55
56int main(){
57 int T = read();
58 while(T--){
59 N = read();
60 for(int i = 1; i <= N; ++i)task[i].s = read(), task[i].t = read(), task[i].w = read();
61 sort(task + 1, task + N + 1, [](const Task &a, const Task &b)->bool{return a.s < b.s;});
62 int l = 0, r = 21000000, ans(-1);
63 while(l <= r){
64 int mid = (l + r) >> 1;
65 if(Check(mid))ans = mid, r = mid - 1;
66 else l = mid + 1;
67 }printf("%d\n", ans);
68 }
69 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
70 return 0;
71}
72
73template < typename T >
74inline T read(void){
75 T ret(0);
76 int flag(1);
77 char c = getchar();
78 while(c != '-' && !isdigit(c))c = getchar();
79 if(c == '-')flag = -1, c = getchar();
80 while(isdigit(c)){
81 ret *= 10;
82 ret += int(c - '0');
83 c = getchar();
84 }
85 ret *= flag;
86 return ret;
87}
考虑将问题转化为求每个点被涂黑的期望并利用线性性求和,考虑正难则反,用
暴力求解期望
离线询问差分一下算点的贡献就行,奇怪题。
update-2023_02_21 初稿