#include <bits/stdc++.h>
// hashing ? prolly hard
using int64_t = int64_t;
template <typename T>
struct FenwickTree{
// 0 indexed
// easily can be modified
// to answer add range query point.
#define lsb(x) ((x) & (-x))
const bool zero_indexed = true;
int n;
std::vector<T> tab;
FenwickTree () {}
FenwickTree (int _n) : n(_n) {
tab.assign(n + 1, T());
}
void dodaj(int pos, T val) {
if(zero_indexed) pos = pos + 1;
while(pos <= n){
tab[pos] += val;
pos += lsb(pos);
}
}
// uwaga z ustaw + range updates
void ustaw(int pos, T val) {
T at_now = suma(pos, pos);
dodaj(pos, -at_now + val);
}
void ustaw2(int pos, T val){
T at_now = suma(pos);
dodaj(pos, -at_now + val);
dodaj(pos+1, -(-at_now + val));
}
T suma(int pos) {
if(zero_indexed) pos = pos + 1;
T res = T();
while(pos > 0){
res += tab[pos];
pos -= lsb(pos);
}
return res;
}
T suma(int l, int r){
return suma(r) - (l >= 1 ? suma(l - 1) : T());
}
};
int main(){
using namespace std;
ios::sync_with_stdio(false), cin.tie(nullptr);
string a, b, c;
cin >> a >> b >> c;
int n = (int)a.size();
assert(n == (int)b.size());
assert(n == (int)c.size());
vector<vector<int>> dig(n, vector<int> (3));
vector<int> f(n);
for(int i = 0;i < n;i++){
dig[i][0] = (a[i] - '0');
dig[i][1] = (b[i] - '0');
dig[i][2] = (c[i] - '0');
if((dig[i][0] + dig[i][1]) % 10 == dig[i][2]){
f[i] = 1;
} else if((dig[i][0] + dig[i][1] + 1) % 10 == dig[i][2]){
f[i] = 2;
} else {
f[i] = 3; // BAD!
}
}
vector<vector<int>> g(n, vector<int> (2, n));
// leftmost digit such that the sum is okay
// n if its never okay
if(f[0] == 1) g[0][0] = 0;
if(f[0] == 2) g[0][1] = 0;
for(int i = 1;i < n;i++){
// Case #1: we don't propagate 1 from the right
if(dig[i][0] + dig[i][1] < 10){
if(f[i] == 1){
g[i][0] = i;
g[i][0] = min(g[i][0], g[i - 1][0]);
}
// f[i] = 2 => nie da się bo nie dostaje
} else {
if(f[i] == 1){
g[i][0] = i;
g[i][0] = min(g[i][0], g[i - 1][1]);
}
}
// Case #2: we propagate a 1 from the right
if(dig[i][0] + dig[i][1] + 1 < 10){
if(f[i] == 2){
g[i][1] = i;
g[i][1] = min(g[i][1], g[i - 1][0]);
}
} else {
if(f[i] == 2){
g[i][1] = i;
g[i][1] = min(g[i][1], g[i - 1][1]);
}
}
}
vector<int> normal(n);
for(int i = 0;i < n;i++){
if(dig[i][0] + dig[i][1] < 10){
normal[i] = 1;
}
}
int64_t ans = 0;
//~ for(int i = 0;i < n;i++){
//~ std::cerr << " i = " << i << " g[i][0]: " << g[i][0] << " g[i][1]: " << g[i][1] << std::endl;
//~ int64_t add = max(int64_t(0), i - g[i][0] + int64_t(1));
//~ ans += add;
//~ if(g[i][0] == n) continue;
//~ int left = g[i][0];
//~ // okay but we need to exclude the ones that propagate one because
//~ // we cannot end with them.
//~ std::cerr << " >> getNormal(left, i): " << getNormal(left, i) << std::endl;
//~ ans += getNormal(left, i);
//~ }
FenwickTree<int64_t> fen(n + 2);
//~ for(int i = 0;i < n;i++){
//~ // okay i am the last one
//~ if(!normal[i] || f[i] == 3) continue;
//~ if(dig[i][0] + dig[i][1] + 1 == 10 && f[i] == 2) continue;
//~ // count the number of g[j][0] such that g[j][0] <= i
//~ for(int j = i;j < n;j++){
//~ if(g[j][0] <= i){
//~ ans += 1;
//~ }
//~ }
//~ }
// speedup
for(int i = n-1;i >= 0;i--){
fen.dodaj(g[i][0], 1);
if(!normal[i] || f[i] == 3) continue;
if(dig[i][0] + dig[i][1] + 1 == 10 && f[i] == 2) continue;
ans += fen.suma(0,i);
}
cout << ans << '\n';
return 0;
}
/*
445195
646335
234530
*/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | #include <bits/stdc++.h> // hashing ? prolly hard using int64_t = int64_t; template <typename T> struct FenwickTree{ // 0 indexed // easily can be modified // to answer add range query point. #define lsb(x) ((x) & (-x)) const bool zero_indexed = true; int n; std::vector<T> tab; FenwickTree () {} FenwickTree (int _n) : n(_n) { tab.assign(n + 1, T()); } void dodaj(int pos, T val) { if(zero_indexed) pos = pos + 1; while(pos <= n){ tab[pos] += val; pos += lsb(pos); } } // uwaga z ustaw + range updates void ustaw(int pos, T val) { T at_now = suma(pos, pos); dodaj(pos, -at_now + val); } void ustaw2(int pos, T val){ T at_now = suma(pos); dodaj(pos, -at_now + val); dodaj(pos+1, -(-at_now + val)); } T suma(int pos) { if(zero_indexed) pos = pos + 1; T res = T(); while(pos > 0){ res += tab[pos]; pos -= lsb(pos); } return res; } T suma(int l, int r){ return suma(r) - (l >= 1 ? suma(l - 1) : T()); } }; int main(){ using namespace std; ios::sync_with_stdio(false), cin.tie(nullptr); string a, b, c; cin >> a >> b >> c; int n = (int)a.size(); assert(n == (int)b.size()); assert(n == (int)c.size()); vector<vector<int>> dig(n, vector<int> (3)); vector<int> f(n); for(int i = 0;i < n;i++){ dig[i][0] = (a[i] - '0'); dig[i][1] = (b[i] - '0'); dig[i][2] = (c[i] - '0'); if((dig[i][0] + dig[i][1]) % 10 == dig[i][2]){ f[i] = 1; } else if((dig[i][0] + dig[i][1] + 1) % 10 == dig[i][2]){ f[i] = 2; } else { f[i] = 3; // BAD! } } vector<vector<int>> g(n, vector<int> (2, n)); // leftmost digit such that the sum is okay // n if its never okay if(f[0] == 1) g[0][0] = 0; if(f[0] == 2) g[0][1] = 0; for(int i = 1;i < n;i++){ // Case #1: we don't propagate 1 from the right if(dig[i][0] + dig[i][1] < 10){ if(f[i] == 1){ g[i][0] = i; g[i][0] = min(g[i][0], g[i - 1][0]); } // f[i] = 2 => nie da się bo nie dostaje } else { if(f[i] == 1){ g[i][0] = i; g[i][0] = min(g[i][0], g[i - 1][1]); } } // Case #2: we propagate a 1 from the right if(dig[i][0] + dig[i][1] + 1 < 10){ if(f[i] == 2){ g[i][1] = i; g[i][1] = min(g[i][1], g[i - 1][0]); } } else { if(f[i] == 2){ g[i][1] = i; g[i][1] = min(g[i][1], g[i - 1][1]); } } } vector<int> normal(n); for(int i = 0;i < n;i++){ if(dig[i][0] + dig[i][1] < 10){ normal[i] = 1; } } int64_t ans = 0; //~ for(int i = 0;i < n;i++){ //~ std::cerr << " i = " << i << " g[i][0]: " << g[i][0] << " g[i][1]: " << g[i][1] << std::endl; //~ int64_t add = max(int64_t(0), i - g[i][0] + int64_t(1)); //~ ans += add; //~ if(g[i][0] == n) continue; //~ int left = g[i][0]; //~ // okay but we need to exclude the ones that propagate one because //~ // we cannot end with them. //~ std::cerr << " >> getNormal(left, i): " << getNormal(left, i) << std::endl; //~ ans += getNormal(left, i); //~ } FenwickTree<int64_t> fen(n + 2); //~ for(int i = 0;i < n;i++){ //~ // okay i am the last one //~ if(!normal[i] || f[i] == 3) continue; //~ if(dig[i][0] + dig[i][1] + 1 == 10 && f[i] == 2) continue; //~ // count the number of g[j][0] such that g[j][0] <= i //~ for(int j = i;j < n;j++){ //~ if(g[j][0] <= i){ //~ ans += 1; //~ } //~ } //~ } // speedup for(int i = n-1;i >= 0;i--){ fen.dodaj(g[i][0], 1); if(!normal[i] || f[i] == 3) continue; if(dig[i][0] + dig[i][1] + 1 == 10 && f[i] == 2) continue; ans += fen.suma(0,i); } cout << ans << '\n'; return 0; } /* 445195 646335 234530 */ |
English