9.5聯合作戰戰果

1.處理內容

字符串部

kmp 1題

trie 1題

AC自動機 1題

數學幾何部

zz平面幾何暴力 1題

快速冪裸版 1題

高斯消元 1題

動態規劃部

裸01揹包 1題

裸數位DP 1題

裸斜率優化DP 2題

2.字符串部

(1)kmp

照例甩題面http://codevs.cn/problem/1204/

直接甩代碼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
inline int read(){
	int i=0,f=1;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar())
		if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar())
		i=(i<<3)+(i<<1)+(ch^48);
	return i*f;
}
int buf[1024];
inline void write(int x){
	if(!x){putchar('0');return ;}
	if(x<0){putchar('-');x=-x;}
	while(x){buf[++buf[0]]=x%10,x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+48);
	return ;
}
char a[111],b[111];
int nxt[111],lena,lenb;
signed main(){
	scanf("%s%s",a+1,b+1);
	lena=strlen(a+1);
	lenb=strlen(b+1);
	for(int i=2,j=0;i<=lenb;++i){
		while(j&&b[i]!=b[j+1]) j=nxt[j];
		if(b[i]==b[j+1]) ++j;
		nxt[i]=j;
	}
	for(int i=1,j=0;i<=lena;++i){
		while(j&&a[i]!=b[j+1]) j=nxt[j];
		if(a[i]==b[j+1]) ++j;
		if(j==lenb){
			write(i-j+1);
			return 0;
		}
	}
	return 0;
}
(2)shortest prefixes

題面:給定n個單詞,對於每個單詞,求能夠唯一表示該單詞的前綴,如果沒有則輸出單詞本身

    還是甩個鏈接http://poj.org/problem?id=2001

直接建trie樹隨便跑一跑就可以了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
inline int read(){
	int i=0,f=1;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar())
		if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar())
		i=(i<<3)+(i<<1)+(ch^48);
	return i*f;
}
int buf[1024];
inline void write(int x){
	if(!x){putchar('0');return ;}
	if(x<0){putchar('-');x=-x;}
	while(x){buf[++buf[0]]=x%10,x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+48);
	return ;
}
struct Dic{
	int nxt[26],tag;
}dic[22222];
char word[1111][22];
int cnt,tot;
void insert(char s[]){
	int pos=0,len=strlen(s+1);
	for(int i=1;i<=len;++i){
		++dic[pos].tag;
		if(!dic[pos].nxt[s[i]-'a'])
			dic[pos].nxt[s[i]-'a']=++cnt;
		pos=dic[pos].nxt[s[i]-'a'];
	}
	++dic[pos].tag;
	return ;
}
void get(char s[]){
	int pos=0,len=strlen(s+1),site=-1;
	for(int i=1;i<=len;++i){
		if(dic[pos].tag==1) break;
		printf("%c",s[i]);
		pos=dic[pos].nxt[s[i]-'a'];
	}
	return ;
}
signed main(){
	tot=1;
	while(scanf("%s",word[tot]+1)!=EOF){
		insert(word[tot]);
		++tot;
	}
	for(int i=1;i<=tot;++i){
		printf("%s ",word[i]+1);
		get(word[i]);
		puts(" ");
	}
	return 0;
}

(3)文本生成器(JSOI2007)

題面:見鏈接http://www.lydsy.com/JudgeOnline/problem.php?id=1030

分析:利用容斥求不合法方案數,dp一下即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#define mod 10007
using namespace std;
inline long long read(){
	long long i=0,f=1;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar())
		if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar())
		i=(i<<3)+(i<<1)+(ch^48);
	return i*f;
}
int buf[1024];
inline void write(long long x){
	if(!x){putchar('0');return ;}
	if(x<0){putchar('-');x=-x;}
	while(x){buf[++buf[0]]=x%10,x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+48);
	return ;
}
struct D{
	int son[26],tag,fail;
}dic[6666];
int now,n,m,f[111][6666],ans,redu;
char word[111];
void insert(){
	int len=strlen(word);
	int pos=0;
	for(int i=0;i<len;++i){
		if(!dic[pos].son[word[i]-'A'])
			dic[pos].son[word[i]-'A']=++now;
		pos=dic[pos].son[word[i]-'A'];
	}
	dic[pos].tag=1;
	return ;
}
void buildfail(){
	static int que[11111];
	int q=0;
	for(int i=0;i<26;++i)
		if(dic[0].son[i]) que[++q]=dic[0].son[i];
	for(int i=1;i<=q;++i){
		int nowpos,nxtpos,failpos;
		nowpos=que[i];
		for(int j=0;j<26;++j){
			failpos=dic[nowpos].fail;
			while(!dic[failpos].son[j])
				failpos=dic[failpos].fail;
			nxtpos=dic[nowpos].son[j];
			failpos=dic[failpos].son[j];
			if(nxtpos){
				dic[nxtpos].fail=failpos;
				if(dic[failpos].tag) dic[nxtpos].tag=1;
				que[++q]=nxtpos;
			}else
				dic[nowpos].son[j]=failpos;
		}
	}
}
int ksm(int a,int b){
	int ret=1;
	while(b){
		if(b&1) ret=(ret*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ret;
}
signed main(){
	n=read();m=read();
	for(int i=1;i<=n;++i){
		scanf("%s",word);
		insert();
	}
	for(int i=0;i<26;++i)
		if(!dic[0].son[i]) dic[0].son[i]=++now;
	buildfail();
	f[0][0]=1;
	for(int i=1;i<=m;++i)
		for(int j=0;j<=now;++j){
			if(dic[j].tag||!f[i-1][j]) continue;
			for(int k=0;k<26;++k)
				f[i][dic[j].son[k]]=(f[i][dic[j].son[k]]+f[i-1][j])%mod;
		}
	ans=ksm(26,m);
	for(int i=1;i<=now;++i)
		if(!dic[i].tag)
			redu=(redu+f[m][i])%mod;
	write((ans-redu+mod)%mod);
	return 0;
}
3.數學幾何部

(1)line(bzoj1610)

著名的bzoj非權限第七頁

來個著名dalao黃學長的題面鏈接http://hzwer.com/2602.html

隨便瞎搞搞,幾乎不動腦(set自帶去重)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<set>
using namespace std;
inline int read(){
	int i=0,f=1;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar())
		if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar())
		i=(i<<3)+(i<<1)+(ch^48);
	return i*f;
}
int buf[1024];
inline void write(int x){
	if(!x){putchar('0');return ;}
	if(x<0){putchar('-');x=-x;}
	while(x){buf[++buf[0]]=x%10,x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+48);
	return ;
}
set<double> tank;
int n,x[222],y[222];
double xx,yy,slope;
signed main(){
	n=read();
	for(int i=1;i<=n;++i){
		x[i]=read();
		y[i]=read();
	}
	for(int i=1;i<=n;++i)
		for(int j=i+1;j<=n;++j){
				xx=x[i]-x[j];
				yy=y[i]-y[j];
				slope=0;
				if(xx==0) slope=9999;
				else slope=yy/xx;
				tank.insert(slope);
			}
	write(int(tank.size()));
	return 0;
}
(2)越獄(HNOI2008)

不告訴你題面是有n房m宗教,相鄰房間宗教不同http://codevs.cn/problem/1851/

分析:依然容斥,今天是不是該改名叫容斥聯合作戰...

   總方案數-安全方案數即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#define mod 100003 
using namespace std;
inline long long read(){
	long long i=0,f=1;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar())
		if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar())
		i=(i<<3)+(i<<1)+(ch^48);
	return i*f;
}
int buf[1024];
inline void write(long long x){
	if(!x){putchar('0');return ;}
	if(x<0){putchar('-');x=-x;}
	while(x){buf[++buf[0]]=x%10,x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+48);
	return ;
}
long long m,n; 
long long ksm(long long a,long long b){
	long long ret=1;
	while(b){
		if(b&1) ret=(ret*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ret;
}
signed main(){
	m=read();n=read();
	write((ksm(m,n)-(m*ksm(m-1,n-1)%mod)+mod)%mod);
	return 0;
}
(3)著名模板題sphere球形空間產生器(JSOI2008)

經典高斯消元,直接甩鏈接http://www.lydsy.com/JudgeOnline/problem.php?id=1013

該題自帶分析

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#define eps 1e-7
using namespace std;
inline long long read(){
	long long i=0,f=1;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar())
		if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar())
		i=(i<<3)+(i<<1)+(ch^48);
	return i*f;
}
int buf[1024];
inline void write(long long x){
	if(!x){putchar('0');return ;}
	if(x<0){putchar('-');x=-x;}
	while(x){buf[++buf[0]]=x%10,x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+48);
	return ;
}
int n,m;
double matrix[14][14],cur[14][14];
void gauss(){
	for(int i=1;i<=n;++i){
		int maxn;double tmp;
		maxn=i;
		for(int j=i+1;j<=m;++j)
			if(fabs(matrix[j][i])>fabs(matrix[maxn][i])) maxn=j;
		if(maxn!=i)
			for(int j=1;j<=m;++j)
				swap(matrix[i][j],matrix[maxn][j]);
		tmp=matrix[i][i];
		for(int j=i+1;j<=m;++j)
			matrix[i][j]/=tmp;
		for(int j=1;j<=n;++j)
			if(j!=i){
				tmp=matrix[j][i];
				for(int k=i;k<=m;++k)
					matrix[j][k]-=matrix[i][k]*tmp;
			}
	}
	return ;
}
signed main(){
	n=read();m=n+1;
	for(int i=0;i<=n;++i)
		for(int j=1;j<=n;++j)
			scanf("%lf",&cur[i][j]);
	for(int i=1;i<=n;++i){
		int j=i-1;double d=0;
		for(int k=1;k<=n;++k){
			matrix[i][k]=(cur[i][k]-cur[j][k])*2;
			d+=(cur[i][k]+cur[j][k])*(cur[i][k]-cur[j][k]);
		}
		matrix[i][m]=d;
	}
	gauss();
	for(int i=1;i<=n;++i){
		if(matrix[i][m]<eps)
			printf("0.000");
		else
			printf("%.3lf",matrix[i][m]);
		if(i<n) putchar(' ');
	}
	return 0;
}
4.動態規劃部

(1)裝箱問題(luoguP1049)

題意:對於容積V與n個佔據空間分別爲c[1],c[2]...c[n]的填充,求最小剩餘容積

    其實是這樣https://www.luogu.org/problem/show?pid=1049

分析:我都不想說什麼...我什麼都不想說...

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
inline int read(){
	int i=0,f=1;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar())
		if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar())
		i=(i<<3)+(i<<1)+(ch^48);
	return i*f;
}
int buf[1024];
inline void write(int x){
	if(!x){putchar('0');return ;}
	if(x<0){putchar('-');x=-x;}
	while(x){buf[++buf[0]]=x%10,x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+48);
	return ;
}
int v,n,c[33],f[22222];
signed main(){
	v=read();n=read();
	for(int i=1;i<=n;++i)
		c[i]=read();
	f[v]=true;
	for(int i=1;i<=n;++i)
		for(int j=c[i];j<=v;++j)
			if(f[j]==true)
				f[j-c[i]]=true;
	for(int i=0;i<=v;++i)
		if(f[i]==true){
			write(i);
			return 0;
		}
}
(2)windy數(SCOI2009)

黑幕以前的題,數位DP模板

鏈接在這http://www.lydsy.com/JudgeOnline/problem.php?id=1026

分析:按位枚舉,最後疊加即可。注意要把位數不足的情況考慮進來

    這就是以前的省選題吧,可以爲後世之模板

    不知道現在的題目以後是墳典或者是什麼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#define int long long
using namespace std;
inline int read(){
	int i=0,f=1;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar())
		if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar())
		i=(i<<3)+(i<<1)+(ch^48);
	return i*f;
}
int buf[1024];
inline void write(int x){
	if(!x){putchar('0');return ;}
	if(x<0){putchar('-');x=-x;}
	while(x){buf[++buf[0]]=x%10,x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+48);
	return ;
}
int f[15][10][2],sze,a,b,lim[15];
int dp(int x){
	memset(f,0,sizeof(f));
	int tmp=x;sze=0;
	while(tmp){
		lim[++sze]=tmp%10;
		tmp/=10;
	}
	for(int i=0;i<=9;++i)
		if(i<=lim[1]) ++f[1][i][0];
		else ++f[1][i][1];
	for(int i=2;i<=sze;++i)
		for(int j=0;j<=9;++j)
			for(int k=0;k<=9;++k)
				if(abs(j-k)>=2){
					if(j<lim[i])
						f[i][j][0]+=f[i-1][k][1]+f[i-1][k][0];
					else if(j==lim[i]){
						f[i][j][0]+=f[i-1][k][0];
						f[i][j][1]+=f[i-1][k][1];
					}else
						f[i][j][1]+=f[i-1][k][1]+f[i-1][k][0];
				}
	int ret=0;
	for(int i=1;i<lim[sze];++i)
		ret+=f[sze][i][1]+f[sze][i][0];
	ret+=f[sze][lim[sze]][0];
	for(int i=sze-1;i;--i)
		for(int j=1;j<=9;++j)
			ret+=f[i][j][1]+f[i][j][0];
	return ret;
}
signed main(){
	a=read();b=read();
	if(a!=1)
		write(dp(b)-dp(a-1));
	else
		write(dp(b));
	return 0;
}

終於到了今天講的重點斜率優化

(3)玩具裝箱(HNOI2008)

2008彷彿創造了很多奇蹟與經典

題面http://www.lydsy.com/JudgeOnline/problem.php?id=1010

分析:唔其實黃學長寫得挺詳細的,有生之年我爭取補上。

    要說的太多不知道從何說起

    最後還是無奈地甩鏈接http://hzwer.com/2114.html

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
inline long long read(){
	long long i=0,f=1;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar())
		if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar())
		i=(i<<3)+(i<<1)+(ch^48);
	return i*f;
}
int buf[1024];
inline void write(long long x){
	if(!x){putchar('0');return ;}
	if(x<0){putchar('-');x=-x;}
	while(x){buf[++buf[0]]=x%10,x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+48);
	return ;
}
#define stan 55555
long long f[stan],que[stan],length[stan],pre[stan],n,boldl;
double slope(int x,int y){
	return (f[x]-f[y]+length[x]*length[x]-length[y]*length[y])*0.5/(length[x]-length[y]);
}
signed main(){
	n=read();boldl=read()+1;
	for(int i=1;i<=n;++i){
		length[i]=read();
		length[i]+=length[i-1]+1;
		pre[i]=length[i]-boldl;
	}
	int l=1,r=1;que[1]=0;
	for(int i=1;i<=n;++i){
		while(l<r&&slope(que[l],que[l+1])<=pre[i]) ++l;
		f[i]=f[que[l]]+(pre[i]-length[que[l]])*(pre[i]-length[que[l]]);
		while(l<r&&slope(que[r],i)<slope(que[r-1],que[r])) --r;
		que[++r]=i;
	}
	write(f[n]);
	return 0;
}


(4)土地購買(USACO2008.Mar.)

2008的確創造了很多奇蹟與經典...

題面...好像是權限

是這樣,有n塊長方形地(寬可以比長長),可以分成若干組買入,買入一組地的代價是該組地最長的長與最長的寬的乘積,求買n塊地的最小代價

分析:這樣,你其實可以通過一些預處理使其具有單調性

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
inline long long read(){
	long long i=0,f=1;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar())
		if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar())
		i=(i<<3)+(i<<1)+(ch^48);
	return i*f;
}
int buf[1024];
inline void write(long long x){
	if(!x){putchar('0');return ;}
	if(x<0){putchar('-');x=-x;}
	while(x){buf[++buf[0]]=x%10,x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+48);
	return ;
}
#define stan 55555
struct field{
	long long l,w;
}a[stan],land[stan];
int n,tot,bound;
long long f[stan],que[stan];
bool cmp(field a,field b){
	if(a.l!=b.l) return a.l>b.l;
	else return a.w>b.w;
}
double slope(int x,int y){
	return (f[x]-f[y])*1.0/(land[y+1].l-land[x+1].l);
}
signed main(){
	n=read();
	for(int i=1;i<=n;++i){
		a[i].l=read();
		a[i].w=read();
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;++i)
		if(a[i].w>bound){
			bound=a[i].w;
			land[++tot]=a[i];
		}
	int l=1,r=1;que[1]=0;
	for(int i=1;i<=tot;++i){
		while(l<r&&slope(que[l],que[l+1])<land[i].w) ++l;
		int j=que[l];
		f[i]=f[j]+land[j+1].l*land[i].w;
		while(l<r&&slope(que[r],i)<slope(que[r-1],que[r])) --r;
		que[++r]=i;
	}
	write(f[tot]);
	return 0;
}
就這麼樣吧。

就讓晴空如年輕時(雖然現在也還年輕),一樣是藍。

以後我會補分析的

抱歉

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章