1. 程式人生 > 其它 >[Contest on 2021.8.31] 。

[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)\)

,令 \(t_i\) 為在區間 \([l,i]\) 中小於 \(B_i\) 的數字個數,相應地,對應 \(C\) 處理出 \(s_i\),那麼當 \(\forall i\in[l,l+n),s_{i-l+1}=t_i\),這個子序列就是合法的。

這與 \(\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;
}