[Contest on 2021.8.31] 。
\(\text{Fansblog}\)
解法
用威爾遜定理。這裡有個結論:
結論:在 \(10^{18}\) 範圍內,兩個相鄰質數的差在 \(100\) 數量級。
\(\text{Lattice Animals}\)
解法
真的廢啊,連 \(n\le 5\) 的表都打掛了。現在也發現 \(\min(w,h)=2\) 的做法也挺難寫的…
用 set
維護一個圖形,再用一個 set
維護點個數為 \(i\) 的圖形。每次從點個數為 \(i\)
set
中取出圖形,再拓展點,判斷是否合法。
具體需要一個 normalize()
來使圖形緊貼 \(x,y\) 軸。除此之外,還需要實現 rotate()
與 flip()
函式將圖形旋轉 \(90\) 度,沿 \(x\) 軸翻折。\(y\) 軸翻折相當於沿 \(x\) 軸翻折後再旋轉 \(180\) 度。
程式碼
#include <cstdio> #define print(x,y) write(x),putchar(y) template <class T> inline T read(const T sample) { T x=0; char s; bool f=0; while((s=getchar())>'9' or s<'0') f|=(s=='-'); while(s>='0' and s<='9') x=(x<<1)+(x<<3)+(s^48), s=getchar(); return f?-x:x; } template <class T> inline void write(const T x) { if(x<0) { putchar('-'),write(-x); return; } if(x>9) write(x/10); putchar(x%10^48); } #include <set> #include <iostream> using namespace std; int ans[11][11][11]; struct node { int x,y; node() {} node(int X,int Y):x(X),y(Y){} bool operator < (const node &t) const { return (x^t.x)?x<t.x:y<t.y; } }; typedef set<node> poly; typedef poly :: iterator Type; set <poly> buc[11]; set <poly> :: iterator it; int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; poly normalize(const poly &t) { poly r; int xx=t.begin()->x,yy=t.begin()->y; for(Type it=t.begin();it!=t.end();++it) xx=min(xx,it->x), yy=min(yy,it->y); for(Type it=t.begin();it!=t.end();++it) r.insert(node(it->x-xx,it->y-yy)); return r; } poly rotate(const poly &t) { poly r; for(Type it=t.begin();it!=t.end();++it) r.insert(node(it->y,-it->x)); return normalize(r); } poly flip(const poly &t) { poly r; for(Type it=t.begin();it!=t.end();++it) r.insert(node(it->x,-it->y)); return normalize(r); } void ins(const poly &t,const node &p) { poly r=t; r.insert(p); r=normalize(r); int n=r.size(); for(int i=0;i<4;++i) { if(buc[n].count(r)) return; r=rotate(r); } r=flip(r); for(int i=0;i<4;++i) { if(buc[n].count(r)) return; r=rotate(r); } buc[n].insert(r); } void init() { poly cur; cur.insert(node(0,0)); buc[1].insert(cur); for(int siz=1;siz<10;++siz) { for(it=buc[siz].begin();it!=buc[siz].end();++it) for(Type IT=(*it).begin();IT!=(*it).end();++IT) { for(int i=0;i<4;++i) { node t=node(IT->x+dir[i][0],IT->y+dir[i][1]); if(!(it->count(t))) ins(*it,t); } } } for(int siz=1;siz<=10;++siz) { for(int p=1;p<=10;++p) for(int q=1;q<=10;++q) { for(it=buc[siz].begin();it!=buc[siz].end();++it) { int xx=0,yy=0; for(Type i=(*it).begin();i!=(*it).end();++i) xx=max(xx,i->x), yy=max(yy,i->y); if(min(xx,yy)<min(p,q) and max(xx,yy)<max(p,q)) ++ans[siz][p][q]; } } } } int main() { init(); int s,n,m; while(~scanf("%d %d %d",&s,&n,&m)) { if(s>n*m) puts("0"); else print(ans[s][n][m],'\n'); } return 0; }
\(\text{[CEOI 2014] Match}\)
題目描述
給出兩個長度分別為 \(n,m\) 的序列 \(A,B\),求出 \(B\) 的所有長度為 \(n\) 的連續子序列(子串),滿足:序列中第 \(i\) 小的數在序列的 \(A_i\) 位置。其中 \(A\) 是一個排列,\(B\) 中的數字各不相同。
\(2\le n,m\le 10^6,1\le B_i\le 10^9\)。
解法
首先將序列 \(A\) 轉化一下,令 \(C_{A_i}=i\),那麼其實就是求 \(B\) 中長度為 \(n\) 的連續子序列離散化之後與 \(C\) 相同。再轉化一下,對於 \(i\in[l,l+n)\)
這與 \(\mathtt{kmp}\) 很類似,區別就是 \(t_i\) 是需要動態維護的。在撤銷也即令 \(p=nxt_p\) 時,相當於把 \([(i-1)-p+1,(i-1)-nxt_p]\) 從子序列中刪除,需要用一個樹狀陣列維護。可以發現,長度為 \(1\) 是一定可以匹配的,所以也不用特判無解的情況。
分析一下時間複雜度。對於 \(p\),每次只能增加 \(1\),所以最多達到 \(n\)。在撤銷的時候,\(p\) 減 \(1\) 對應一次 \(\mathcal O(\log m)\) 的樹狀陣列修改。所以時間複雜度是 \(\mathcal O((n+m)\cdot \log m)\) 的。
另:還有一個 \(\mathcal O(n)\) 的做法,但我著實沒看懂…
程式碼
#include <cstdio>
#define print(x,y) write(x),putchar(y)
template <class T>
inline T read(const T sample) {
T x=0; char s; bool f=0;
while((s=getchar())>'9' or s<'0')
f|=(s=='-');
while(s>='0' and s<='9')
x=(x<<1)+(x<<3)+(s^48),
s=getchar();
return f?-x:x;
}
template <class T>
inline void write(const T x) {
if(x<0) {
putchar('-'),write(-x);
return;
}
if(x>9) write(x/10);
putchar(x%10^48);
}
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e6+5;
int n,m,c[maxn];
int a[maxn],b[maxn];
int v[maxn],s[maxn];
int nxt[maxn];
vector <int> ans;
int lowbit(int x) {
return x&-x;
}
void add(int x,int k) {
while(x<=m)
c[x]+=k,
x+=lowbit(x);
}
int ask(int x) {
int r=0;
while(x)
r+=c[x],
x-=lowbit(x);
return r;
}
int main() {
n=read(9),m=read(9);
for(int i=1;i<=n;++i) {
int x=read(9);
s[x]=i;
}
for(int i=1;i<=n;++i)
v[i]=ask(s[i]),
add(s[i],1);
for(int i=1;i<=m;++i)
a[i]=b[i]=read(9);
memset(c,0,sizeof c);
int p=0;
for(int i=2;i<=n;++i) {
while(v[p+1]^ask(s[i])) {
for(int j=i-p;j<i-nxt[p];++j)
add(s[j],-1);
p=nxt[p];
}
nxt[i]=++p;
add(s[i],1);
}
memset(c,0,sizeof c);
p=0;
sort(b+1,b+m+1);
for(int i=1;i<=m;++i) {
a[i]=lower_bound(b+1,b+m+1,a[i])-b;
while(p==n or (v[p+1]^ask(a[i]))) {
for(int j=i-p;j<i-nxt[p];++j)
add(a[j],-1);
p=nxt[p];
}
++p;
if(p==n) ans.push_back(i-n+1);
add(a[i],1);
}
print(ans.size(),'\n');
for(auto i:ans)
print(i,' ');
puts("");
return 0;
}