若是有最小答案的话这个答案必定是N和M的lcm
咱们考虑一下什么状况下
\(k \frac{L}{N} = h \frac{L}{M}\)且\(k,g\)互质
显然是在\(k = \frac{N}{gcd(N,M)},h = \frac{M}{gcd(N,M)}\)的时候成立node
咱们只要不断枚举\(k * i,h * i\)判断两个串里这个位置的数是否相同便可ios
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define enter putchar('\n') #define space putchar(' ') //#define ivorysi #define MAXN 100005 typedef long long int64; using namespace std; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } int64 N,M; char S[MAXN],T[MAXN]; int64 gcd(int64 a,int64 b) { return b == 0 ? a : gcd(b,a % b); } int64 lcm(int64 a,int64 b) { return a * b / gcd(a,b); } void Solve() { read(N);read(M); scanf("%s",S + 1);scanf("%s",T + 1); int64 c = lcm(N,M); int64 a = c / M,b = c / N; for(int i = 0 ; i <= N ; ++i) { if(i * a + 1 > N || i * b + 1 > M) break; if(S[i * a + 1] != T[i * b + 1]) {puts("-1");return;} } out(c);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); return 0; }
我计数计的挺麻烦的c++
我是对于每一段统计一下这一段会被哪些序列统计到ui
显然对于长度为K的一个段,除掉最靠前的一段和最靠后的一段,中间的每一个段,若是这一段被取了,那么这个操做序列一定包含一个子序列,就是这一段两侧被提早取了,中间是K个数的任意排列spa
而后咱们对于每一个长度特殊处理最前一段和最后一段(由于他们的端点只有一个),对于中间的序列计算排列个数,而中间序列的代价总和能够经过前缀和的前缀和快速算出来code
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define enter putchar('\n') #define space putchar(' ') //#define ivorysi #define MAXN 100005 typedef long long int64; using namespace std; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } const int MOD = 1000000007; int N,A[MAXN],fac[MAXN],invfac[MAXN],inv[MAXN],sum[MAXN],sum_of_sum[MAXN]; int inc(int a,int b) { return a + b >= MOD ? a + b - MOD : a + b; } int mul(int a,int b) { return 1LL * a * b % MOD; } void update(int &x,int y) { x = inc(x,y); } int C(int n,int m) { if(n < m) return 0; return mul(fac[n],mul(invfac[m],invfac[n - m])); } void Solve() { read(N); for(int i = 1 ; i <= N ; ++i) { read(A[i]); sum[i] = inc(sum[i - 1],A[i]); sum_of_sum[i] = inc(sum_of_sum[i - 1],sum[i]); } inv[1] = 1; for(int i = 2 ; i <= N ; ++i) { inv[i] = mul(inv[MOD % i],MOD - MOD / i); } fac[0] = invfac[0] = 1; for(int i = 1 ; i <= N ; ++i) { fac[i] = mul(fac[i - 1],i); invfac[i] = mul(invfac[i - 1],inv[i]); } int ans = 0; for(int i = 1 ; i <= N ; ++i) { if(i == N) update(ans,mul(sum[N],fac[N])); else { update(ans,mul(inc(sum[i],inc(sum[N],MOD - sum[N - i])),mul(mul(fac[i],C(N,i + 1)),fac[N - i - 1]))); if(i < N - 1) { int t = inc(sum_of_sum[N - 1],MOD - sum_of_sum[i]); update(t,MOD - sum_of_sum[N - i - 1]); update(ans,mul(t,mul(mul(mul(2,fac[i]),C(N,i + 2)),fac[N - i - 2]))); } } } out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); return 0; }
显然若是最优的话,答案至少为这2×N个数里前N小的数的和
咱们把全部前N小的数标出来,称为1,后N个数称为0
那么一个点有4种状况 01 10 00 11
后两种个数相同element
若是咱们有00(咱们必定会有相同个数的11)的话,那么必定可行,为何,由于咱们把01首尾相接成一个01,把10首尾相接成一个10,而后01 00 10 11就能够了rem
若是咱们只有10或只有01,也必定可行get
惟一取不到这个解的是有10,而且有01,并且不存在00
那么这个时候咱们枚举两个1相撞时1的值(若是这个1和另外一个1相撞的时候它不是最小值也不要紧,最后会被更新掉),同时计算一下两个0相撞时0能取到的最大值,能够用一个set维护,由于咱们须要删掉枚举的1所带的那个0,除了它所在的类型只有1个的状况string
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define enter putchar('\n') #define space putchar(' ') //#define ivorysi #define MAXN 100005 typedef long long int64; using namespace std; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } int N; int64 p[MAXN][2],sum,ans,t3; int L[MAXN],R[MAXN],tot,ty[MAXN],cnt[10]; pii pos[MAXN * 2]; multiset<int64> S; bool cmp(pii a,pii b) { return p[a.fi][a.se] < p[b.fi][b.se]; } void Solve() { read(N); for(int i = 1 ; i <= N ; ++i) { read(p[i][1]);read(p[i][0]); ans += p[i][1] + p[i][0]; pos[++tot] = mp(i,0); pos[++tot] = mp(i,1); } sort(pos + 1,pos + tot + 1,cmp); for(int i = 1 ; i <= tot / 2 ; ++i) { sum += p[pos[i].fi][pos[i].se]; if(!pos[i].se) L[pos[i].fi] = 1; else R[pos[i].fi] = 1; S.insert(p[pos[i].fi][pos[i].se]); } for(int i = 1 ; i <= N ; ++i) { if(L[i] && !R[i]) {ty[i] = 1;cnt[1]++;} if(!L[i] && R[i]) {ty[i] = 2;cnt[2]++;} if(!L[i] && !R[i]) {ty[i] = 3;cnt[3]++;} if(L[i] && R[i]) {ty[i] = 4;cnt[4]++;} } if(!cnt[1] || !cnt[2] || cnt[3]) {out(sum);enter;return;} for(int i = tot / 2 + 1 ; i <= tot ; ++i) { int u = pos[i].fi; if(cnt[ty[u]] != 1) { S.erase(S.find(p[u][pos[i].se ^ 1])); ans = min(ans,sum + p[pos[i].fi][pos[i].se] - *(--S.end())); S.insert(p[u][pos[i].se ^ 1]); } else ans = min(ans,sum + p[pos[i].fi][pos[i].se] - *(--S.end())); } out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); return 0; }
这题看起来很繁琐,可是实际上逻辑很简单
\(dp[i][j]\)表示一个联通块标记为\(i\)为最小的标号,\(j\)为最大的标号,这样的方案有多少个
首先要知足初始的时候\(i,j\)之间的点没有连到外部的点
而后计算方案是\(g(x)\)
x是\(i,j\)之间没有匹配的点的个数,\(g(x) = 1*3*5...(x - 3)(x - 1)\)
而后再减掉不合法的方案
\(dp[i][j] -= dp[i][k] * g(z)\)z是\(k + 1,j\)中没有匹配过的点
最后输出的时候还要乘上一个\(g(y)\)y表示全部除了\(i,j\)以外未匹配的点
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #define enter putchar('\n') #define space putchar(' ') #define fi first #define se second #define mp make_pair #define MAXN 200005 //#define ivorysi #define pii pair<int,int> using namespace std; typedef long long int64; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {putchar('-');x = -x;} if(x >= 10) out(x / 10); putchar('0' + x % 10); } const int MOD = 1000000007; int N,K; int A[305],B[305]; int cnt[605][605],dp[605][605],g[605]; bool vis[605][605]; bool in(int a,int l,int r) { return a >= l && a <= r; } int inc(int a,int b) { return a + b >= MOD ? a + b - MOD : a + b; } int mul(int a,int b) { return 1LL * a * b % MOD; } void Solve() { read(N);read(K); for(int i = 1 ; i <= K ; ++i) { read(A[i]);read(B[i]); } g[0] = 1; for(int i = 1 ; i <= 2 * N ; ++i) { if(i & 1) g[i] = 0; else g[i] = mul(g[i - 2],i - 1); } for(int i = 1 ; i <= 2 * N ; ++i) { for(int j = i + 1 ; j <= 2 * N ; ++j) { for(int h = 1 ; h <= K ; ++h) { if(in(A[h],i,j) && in(B[h],i,j)) { ++cnt[i][j]; } else if((!in(A[h],i,j) && in(B[h],i,j)) || (in(A[h],i,j) && !in(B[h],i,j))) { vis[i][j] = 1; break; } } } } for(int d = 2 ; d <= 2 * N ; d += 2) { for(int i = 1 ; i <= 2 * N ; ++i) { int j = i + d - 1; if(j > 2 * N) break; if(vis[i][j]) continue; int x = j - i + 1 - 2 * cnt[i][j]; dp[i][j] = g[x]; for(int h = i + 1 ; h < j ; h += 2) { if(!dp[i][h]) continue; x = j - h - 2 * cnt[h + 1][j]; dp[i][j] = inc(dp[i][j],MOD - mul(dp[i][h],g[x])); } } } int ans = 0; for(int i = 1 ; i <= 2 * N ; ++i) { for(int j = i + 1 ; j <= 2 * N ; j += 2) { int y = 2 * N - (j - i + 1 - 2 * cnt[i][j]) - 2 * K; ans = inc(ans,mul(dp[i][j],g[y])); } } out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }
咱们须要已知部分\(X\)和\(Y\)的状况下,知道后面的数能不能使得最终状况合法
咱们设\(X\)高元素的个数为\(C_x\),\(Y\)高元素个数为\(C_y\)
咱们还须要两个高元素序列\(a,b\)知足\(C_x + |a| = C_y + |b|\)
咱们能够保证\(a,b\)至少有一个,其中全部的高元素都是p原来的高元素,证实这个,咱们只要找到两个合法的序列,而后每次减小两个序列中高元素,直到不能减了
这样的话咱们设\(a\)全是P原来的高元素组成的序列
而后咱们决定一下\(b\),\(b\)肯定了\(a\)就自动是未选的全部高元素了
设\(b\)中的高元素有\(k\)个是P中的高元素,\(m\)是非高元素,剩下的序列中有Q个是高元素
那么咱们知足
\(C_x + Q - k = C_y + |b|\)
\(C_x + Q - k = C_y + k + m\)
\(2k + m = C_x - C_y + Q\)
也就是咱们设全部高元素长度为2,非高元素长度为1,求一个上升子序列,看看长度是否正好为一个常数
咱们只须要分奇偶性找一个最长的升子序列,和这个常数比较一下就行
须要用线段树维护dp状态
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define MAXN 200005 //#define ivorysi #define space putchar(' ') #define enter putchar('\n') using namespace std; typedef long long int64; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } int N,P[MAXN],val[MAXN],ans[MAXN],curx,cury; struct node { int maxv,L,R,lc,rc; }tr[MAXN * 20]; int rt[2],Ncnt; void build(int &u,int L,int R,int v) { u = ++Ncnt; tr[u].L = L;tr[u].R = R; tr[u].maxv = v; if(L == R) return; int mid = (L + R) >> 1; build(tr[u].lc,L,mid,v); build(tr[u].rc,mid + 1,R,v); } void Change(int u,int pos,int v) { if(tr[u].L == tr[u].R) {tr[u].maxv = v;return;} int mid = (tr[u].L + tr[u].R) >> 1; if(pos <= mid) Change(tr[u].lc,pos,v); else Change(tr[u].rc,pos,v); tr[u].maxv = max(tr[tr[u].lc].maxv,tr[tr[u].rc].maxv); } int Query(int u,int l,int r) { if(tr[u].L == l && tr[u].R == r) return tr[u].maxv; int mid = (tr[u].L + tr[u].R) >> 1; if(r <= mid) return Query(tr[u].lc,l,r); else if(l > mid) return Query(tr[u].rc,l,r); else return max(Query(tr[u].lc,l,mid),Query(tr[u].rc,mid + 1,r)); } void Solve() { read(N); for(int i = 1 ; i <= N ; ++i) read(P[i]); int cur = 0,Q = 0; for(int i = 1 ; i <= N ; ++i) { cur = max(cur,P[i]); if(cur == P[i]) {val[i] = 2;++Q;} else val[i] = 1; } build(rt[0],1,N + 1,0);build(rt[1],1,N + 1,-2 * N); for(int i = N ; i >= 1 ; --i) { int tmp[2]; for(int j = 0 ; j < 2 ; ++j) tmp[j] = Query(rt[j],P[i] + 1,N + 1); for(int j = 0 ; j < 2 ; ++j) { if(tmp[j] + val[i] > 0) { int t = (tmp[j] + val[i]) & 1; Change(rt[t],P[i],tmp[j] + val[i]); } } } int len[2] = {0,0},mx_num[2] = {0,0}; for(int i = 1 ; i <= N ; ++i) { ans[i] = -1; Change(rt[0],P[i],0);Change(rt[1],P[i],-2 * N); if(val[i] == 2) --Q; for(int k = 0 ; k < 2 ; ++k) { int nxt_len[2],nxt_mx_num[2]; memcpy(nxt_len,len,sizeof(len)); memcpy(nxt_mx_num,mx_num,sizeof(mx_num)); nxt_mx_num[k] = max(nxt_mx_num[k],P[i]); if(nxt_mx_num[k] == P[i]) ++nxt_len[k]; if(i == N) { if(nxt_len[0] == nxt_len[1]) {ans[i] = k;break;} continue; } bool flag = 0; for(int j = 0 ; j < 2 ; ++j) { int t = nxt_len[j] - nxt_len[j ^ 1] + Q; if(t >= 0 && Query(rt[t & 1],nxt_mx_num[j ^ 1] + 1,N + 1) >= t) {flag = 1;break;} } if(flag) { ans[i] = k; memcpy(len,nxt_len,sizeof(len)); memcpy(mx_num,nxt_mx_num,sizeof(mx_num)); break; } } if(ans[i] < 0) { puts("-1");return; } } for(int i = 1 ; i <= N ; ++i) putchar('0' + ans[i]); enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }