给定
类似的原题是 Vijos-1065 最小数字倍数,该题要求仅存在对应数。
一道很简单但做得很麻烦的题,首先考虑的是
转移及其复杂,需要考虑很多细节,也不知道我咋想出来的,奇奇怪怪。
xxxxxxxxxx133123
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
23/*2437 9250 1 2 3 4 5 6 7 926
27233333 8282 3 4 5 6 7 8 929*/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}存在
大概想出来贪心了,左端点排序然后右端点排序建堆,但是取元素然后区间覆盖的时候一直没太想好怎么处理,主要的问题是卡在了,建树最大实际上应该是
xxxxxxxxxx133123
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/*253265271 4 2283 6 3294 5 2304 7 2315 8 1326331 7 25344 8 10357 10 5368 11 53710 13 103811 13 53984015 18 104120 24 16428 15 334311 14 14441 6 164516 19 12463 5 124722 25 1048*/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}存在初始全为白色的序列,每次从
手推了一下次数为
xxxxxxxxxx92123
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
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}给定序列
xxxxxxxxxx97123
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
23/*245 4251 5 3 3 1263 3 4274 4 5282 1 4295 3 530*/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,记录前驱以及具体数位值,跑一遍即可。
xxxxxxxxxx85123
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
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}问题关键在于转换,即不去枚举事件,而去枚举时间,这样贪心更显然且极好维护。
xxxxxxxxxx87123
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
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 初稿