URAL - 1996

URAL - 1996 题意: URAL - 1996 给两个长度分别为$n, m$的字节串$A,B$,$A$串的最后一位可以修改,代价为$1$,求使得$B$串为$A$串字串的最小代价 Solution : 因为$A$串只有最后最后一位可以修改,所以可以用KMP求出可能匹配的位置,然后计算每个位置的$cost$ 记$A$串最后一位构成的串为$a$, $B$串的为$b$, 假设$pos(0\le pos \le n-m)是可能匹配的位置$,如果将$b$反转得到$b’$, 在此处的的代价为 $$ \sum_{i+j=pos+m-1} [a_i \ne b’_j ] $$ 而 $$ \sum_{i+j=posm-1} a_j * b’_j $$ 可以算出来相等的$1$的个数$cnt_1$,再将$a,b$串取反,再做一次卷积就可以算出$0$相等的个数$cnt_2$,$ans=m-cnt_1-cnt_2$ #include <cstdio> #include <stack> #include <set> #include <cmath> #include <map> #include <time.h> #include <vector> #include <iostream> #include <string> #include <cstring> #include <algorithm> #include <memory.h> #include <cstdlib> #include <queue> #include <iomanip> #include <unordered_map> #define P pair<int, int> #define LL long long #define LD long double #define PLL pair<LL, LL> #define mset(a, b) memset(a, b, sizeof(a)) #define rep(i, a, b) for (int i = a; i < b; i++) #define PI acos(-1.0) #define random(x) rand() % x #define debug(x) cout << #x << " " << x << "\n" using namespace std; const int inf = 0x3f3f3f3f; const LL __64inf = 0x3f3f3f3f3f3f3f3f; #ifdef DEBUG const int MAX = 2e3 + 50; #else const int MAX = 1e6 + 50; #endif const int mod = 1e9 + 7; #include <complex> namespace FFT { int rev[MAX]; int cnt[MAX]; void fft(complex<double> *a, int n, int inv){ int bit = 0; while((1 << bit) < n) bit++; for(int i = 0; i < n; i++){ rev[i] = (rev[i>>1]>>1) | ((i & 1) << (bit-1)); if(i < rev[i]) swap(a[i], a[rev[i]]); } for(int mid = 1; mid < n; mid <<= 1){ complex<double> wn(cos(PI/mid), inv*sin(PI/mid)); for(int i = 0; i < n; i += (mid<<1)){ complex<double> w(1, 0); for(int j = 0; j < mid; j++, w *= wn){ complex<double> u = a[i+j], t = w * a[i+j+mid]; a[i+j] = u+t, a[i+j+mid] = u-t; } } } } void work(complex<double> *ss, complex<double> *rev_t, int N, int n, int m){ FFT::fft(ss, N, 1); FFT::fft(rev_t, N, 1); for(int i = 0; i <= N; i++) { ss[i] *= rev_t[i]; } FFT::fft(ss, N, -1); for(int i = 0; i <= n-m; i++){ cnt[i] += (int)(ss[i+m-1].real() / N + 0.5); } } }; complex<double> a[MAX],b[MAX]; int x[MAX], y[MAX]; int s[MAX], t[MAX]; complex<double> ss[MAX], rev_t[MAX]; char ch[10]; void input(int *x, int *s, int n){ for(int i = 0; i < n; i++){ scanf("%s", ch); for(int j = 0; j < 6; j++) if(ch[j] == '1') x[i] += 1 << j; s[i] = (ch[7] == '1'); } } struct KMP { int next[MAX]; vector<int> pos; void init(int *x, int n){ next[0] = -1; int k = -1; for(int i = 1; i < n; i++){ while(k > -1 and x[k+1] != x[i]) k = next[k]; if(x[k+1] == x[i]) k++; next[i] = k; } } void work(int *x, int n, int *y, int m){ int k = -1; init(x, n); for(int i =0; i < m; i++){ while(k > -1 and x[k+1] != y[i]) k = next[k]; if(x[k+1] == y[i]) k++; if(k == n-1) { pos.push_back(i-n+1); k = next[k]; } } } }kmp; int main(){ #ifdef DEBUG freopen("in", "r", stdin); #endif int n, m; scanf("%d%d", &n, &m); input(x,s,n); input(y, t, m); kmp.init(y, m); kmp.work(y, m, x, n); if(kmp.pos.empty()){ puts("No"); return 0; } int N = 1; while(N <= n+m) N<<=1; for(int i = 0; i < n; i++) ss[i] = complex<double>(s[i], 0); for(int i = 0; i < m; i++) rev_t[i] = complex<double>(t[m-1-i], 0); FFT::work(ss, rev_t, N, n, m); for(int i = 0; i < n; i++) s[i] ^= 1; for(int i = 0; i < m; i++) t[i] ^= 1; for(int i = 0; i < n; i++) ss[i] = complex<double>(s[i], 0); for(int i = n; i < N; i++) ss[i] = complex<double>(0, 0); for(int i = 0; i < m; i++) rev_t[i] = complex<double>(t[m-i-1], 0); for(int i = m; i < N; i++) rev_t[i] = complex<double>(0, 0); FFT::work(ss, rev_t, N, n, m); int res = inf, id = -1; for(int i = 0; i < kmp.pos.size(); i++){ int pos = kmp.pos[i]; // pos += m-1; int cost = m - FFT::cnt[pos]; if(cost < res){ res = cost, id = kmp.pos[i]; } } puts("Yes"); printf("%d %d\n", res, id+1); return 0; }

📝 February 11, 2020&nbsp;·&nbsp;⌛ 4 min