2018.12.15【NOIP提高組】模擬B組

題目

收集卡片

Description

Star 計劃訂購一本將要發行的週刊雜誌,但他可不是爲了讀書,而是——集卡。已知雜誌將要發行 N 周(也就是 N 期),每期都會附贈一張卡片。Star通過種種途徑,瞭解到 N 期雜誌附贈的卡片種類。Star 只想訂購連續的若干期,並在這些期內收集所有可能出現的種類的卡片。現在他想知道,他最少需要訂購多少期。

Input

第一行一個整數 N;
第二行一個長度爲 N 的字符串,由大寫或小寫字母組成,第 i 個字符表示 第 i 期附贈的卡片種類,每種字符(區分大小寫)表示一種卡片。

Output

輸出一行一個整數,表示 Star 最少訂購的期數。

Sample Input

8
acbbbcca

Sample Output

3

Data Constraint

對於 30%的數據,N ≤ 300;
對於 40%的數據,N ≤ 2000;
對於 60%的數據,N ≤ 5000;
對於 80%的數據,N ≤ 100000;
對於 100%的數據,N ≤ 500000。


基因變異

Description

21 世紀是生物學的世紀,以遺傳與進化爲代表的現代生物理論越來越多的 進入了我們的視野。 如同大家所熟知的,基因是遺傳因子,它記錄了生命的基本構造和性能。 因此生物進化與基因的變異息息相關,考察基因變異的途徑對研究生物學有着 至關重要的作用。現在,讓我們來看這樣一個模型:
1、所有的基因都可以看作一個整數或該整數對應的二進制碼;
2、在 1 單位時間內,基因 x 可能會在其某一個二進制位上發生反轉;
3、在 1 單位時間內,基因 x 可能會遭到可感染基因庫內任一基因 y 的影響 而突變爲 x XOR y。
現在給出可感染基因庫,Q 組詢問,每組給出初始基因與終止基因,請你 分別計算出每種變異最少要花費多少個單位時間。

Input

第 1 行兩個整數 N, Q; 第 2 行 N 個用空格隔開的整數分別表示可感染基因庫內的基因; 接下來 Q 行每行兩個整數 S、T,分別表示初始基因與終止基因。

Output

輸出 Q 行,依次表示每組初始基因到終止基因間最少所花時間。

Sample Input

3 3
1 2 3
3 4
1 2
3 9

Sample Output

2
1
2

Data Constraint

對於 20%的數據,N = 0;
對於額外 40%的數據,1 ≤ Q ≤ 100,所有基因表示爲不超過 10410^4 的非負整 數;
對於 100%的數據,0 ≤ N ≤ 20,1 ≤ Q ≤ 10510^5,所有基因表示爲不超過 10610^6 的 非負整數。


abcd

Description

有4個長度爲N的數組a,b,c,d。現在需要你選擇N個數構成數組e,數組e滿足aieibia_i\leq e_i\leq b_i以及i=1Neici=0\sum^{N}_{i=1}e_i*c_i=0並且使得i=1Neidi\sum^{N}_{i=1}e_i*d_i最大。

Input

輸入文件名爲abcd. in。
輸入文件共 N+1 行。
第 1 行包含1個正整數N。
第 i+1 行包含4個整數a[i],b[i],c[i],d[i]。

Output

輸出文件名爲abcd.out。
輸出共1行,包含1個整數,表示所給出公式的最大值。輸入數據保證一定有解。

Sample Input

Sample1:
5
-1 1 2 5
-2 2 1 2
0 1 1 3
-2 -1 3 10
-2 2 3 9
Sample2:
10
1 10 1 7
-10 10 2 0
-10 10 2 2
-10 10 2 0
1 10 1 0
-10 10 2 0
10 10 2 0
1 10 1 0
-10 10 2 0
1 10 1 0
Sample3:
10
1 10 1 0
-10 10 2 2
-10 10 2 2
-10 10 2 2
1 10 1 0
-10 10 2 2
-10 10 2 2
1 10 1 0
-10 10 2 2
1 10 1 0

Sample Output

Sample1:
2
Sample2:
90
Sample3:
-4

Data Constraint

對於20%的數據,N≤10,-2≤a[i]<b[i]≤2;
對於60%的數據,N≤50, -20≤a[i]<b[i]≤20;
對於100%的數據,N≤200,-25≤a[i]<b[i]≤25,1≤c[i]≤20,0≤d[i] ≤100000。


總結

今天犯了一個錯誤,坑了100分,只有100分了。
在這裏插入圖片描述
第一題:
我先想到了二分答案、前綴和等高深的算法。好不容易纔回過神來,發現這是一道很水很水的雙向指針。在想完第二題後打代碼,考場AC。

第二題:
一開始覺得很神仙,就去看第三題,結果發現第三題更神仙o(╥﹏╥)o
於是決定模擬一下樣例。由於我理解錯了題意,把

在 1 單位時間內,基因 x 可能會在其某一個二進制位上發生反轉;

理解成了可以在1單位時間內翻轉基因 x 的所有二進制位,因此怎麼算也算不出來;等我算完樣例後,驚奇地發現了一個神奇的東西:

把基因 x 變成基因 y 等價於把 0 變成 x^y(即 x 和 y 有多少個不同的位)

於是我欣欣然打了一個DP:設fif_i表示把基因 i 變成0的最少步數。{f0=0fi2j=max(fi2j,fi+1)i&gt;0fiaj=max(fiaj,fi+1)i&gt;0\begin{cases}f_0=0\\f_{i\bigoplus2^j}=\max(f_{i\bigoplus 2^j},f_i+1)&amp;\text{i&gt;0}\\f_{i\bigoplus a_j}=\max(f_{i\bigoplus a_j},f_i+1)&amp;\text{i&gt;0}\end{cases}其中\bigoplus表示xor。
結果發現這個DP有後效性,遂改成記憶化搜索(DFS),結果時間複雜度似乎不太理想。

正常人這個時候都會把DFS改成BFS,然而我卻腦殘了一般,輸出 f 數組,然後在代碼的開頭直接給 f 數組賦初值。

其實這樣是會出錯的,因爲每一個輸入的 a 都不一樣,那麼 f 的值就自然不同了;然而我卻沒有意識到這一點,直接交到OJ上。在這裏插入圖片描述
注意碼量!
是不是很驚人?我TMD2202^{20}那麼大的DP數組賦初值,結果直接編譯錯誤了(OJ能容忍的最長碼量似乎是10510^5byte)
不過話說回來,這樣的實驗似乎是挺有趣的。

正解

T1

雙指針搜索就可以了。
下面就來解釋什麼是雙指針搜索
首先申明一下,這裏的指針並非指數據結構中的那個指針,而是兩個指向數組中位置的變量。我們要兩個指針 l 和 r,分別指向子區間的開頭和結尾。

這個算法常用來解決在大區間中找滿足要求的最長或最短的子區間。它的步驟常是這樣:

若當前區間不滿足要求(有時也可以是滿足要求),且若是該區間向右擴張後可能滿足,即向右擴張可接近要求,則把 r 指針向右移動1個單位,並加上該元素的值;
若當前區間已經超出要求(有時是滿足要求),且該區間向右擴張會不斷遠離要求,則把 l 指針向右移動1個單位。
注意:在所有這些過程中,l 和 r指針永遠向右移動

在這題中,我們先把兩個指針指針指向第一個元素,再執行上面的過程。如果當前區間不包含所有字符,則 r 向右移動;包含所有字符,就把 l 向右移動(因爲我們這道題目是要求最短序列的)。
最後,請注意邊界條件!

T2

這題其實也不難(然而我卻爆0了)
首先,我們可以發現一個顯而易見的規律(不要問我爲什麼想了20分鐘才發現

把基因 x 變成基因 y 等價於把 0 變成 x^y(即 x 和 y 有多少個不同的位)

因此,我們可以先預處理出所有數變成0的最少步數(很容易發現把x變成y等價於把y變成x嘛)
可以從0出發,搜索所有它可以變成的數,若可以更新,就更新它並從它出發進行搜索。
顯然DFS會TLE,我們就要加上記憶化;然而記憶化DFS還是會爆炸,於是我就想到了打表(不要問我爲什麼想不到BFS!!!)
其實用BFS就可以了。。。

T3

這題不少人用水法過了。
其實我們可以把它轉化成一道多重揹包問題:

給出n個物品,每一件可以選aia_ibib_i個,體積爲cic_i,價值爲did_i,恰好填滿一個容量爲0的揹包

對於這個問題,我們可以把範圍轉換成0~b[i]-a[i],那麼選的件數就成了e[i]-a[i],那麼揹包的體積就成了-a[i]*c[i](因爲a[i]幾乎總是小於0),價值是(eiai)di+Σaidi(e_i-a_i)*d_i+\Sigma a_i*d_i
但是這樣DP顯然時超,因此我們要用優化。有兩種:單調隊列和二進制。
這裏說一下二進制優化:

設物品的體積爲x,我們就把它分解成體積爲1,2,4,8,…2k12^{k-1},n2k1n-2^{k-1}的物品。
可以證明,這些物品可以組成0~x中的任意體積。

這樣做就可以了。

代碼

T1

#include<cstdio>
#include<algorithm>
using namespace std;
#define N 500005
struct node
{char ch;int id;}s[N];
int a[N],num[N];
inline bool cmp(node x,node y)
{return x.ch<y.ch;}
int main()
{
	int n,m=1,i,j,l,r,ans=N;
	bool bk;
	scanf("%d\n",&n);
	for(i=1;i<=n;i++) scanf("%c",&s[i].ch),s[i].id=i;
	sort(s+1,s+n+1,cmp);
	a[s[1].id]=1;
	for(i=2;i<=n;i++)
	{
		if(s[i].ch>s[i-1].ch) m++;
		a[s[i].id]=m;
	}
	for(l=r=1,num[a[1]]=1;l<=n;--num[a[l++]])
	{
		bk=1;
		for(;bk&&r<=n;num[a[++r]]++)
		{
			for(j=1;j<=m;j++)
				if(!num[j])
					break;
			if(j>m){bk=0;break;}
		}
		if(bk) break;
		if(r-l+1<ans) ans=r-l+1;
	}
	printf("%d\n",ans);
	return 0;
}

T2

#include<cstdio>
using namespace std;
#define M 1048576
#define N 25
int n,a[N],f[M],data[5110000];
int main()
{
	int m,i,j,x,y,head=0,tail=1;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
	for(i=1;i<M;i++) f[i]=N;
	while(head<tail)
	{
		x=data[++head];
		for(i=1;i<=n;i++)
		{
			if(f[x^a[i]]>f[x]+1)
			{
				f[x^a[i]]=f[x]+1;
				data[++tail]=x^a[i];
			}
		}
		for(i=0;i<20;i++)
		{
			if(f[x^1<<i]>f[x]+1)
			{
				f[x^1<<i]=f[x]+1;
				data[++tail]=x^1<<i;
			}
		}
	}
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y),x^=y;
		printf("%d\n",f[x]);
	}
	return 0;
}

T3

#include<cstdio>
using namespace std;
#define N 205
#define M 100005
#define inf 999999999
int n,m,ans,s,f[M],a[N],b[N],c[N],d[N],w[N*6],v[N*6];
int main()
{
	freopen("abcd.in","r",stdin);
	freopen("abcd.out","w",stdout);
	int i,j,k;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
		m-=a[i]*c[i],ans+=a[i]*d[i];
	}
	for(i=1;i<=n;i++)
	{
		k=b[i]-a[i];
		for(j=1;j<=k;j<<=1)
		{
			w[++s]=j*c[i],v[s]=j*d[i];
			k-=j;
		}
		if(k) w[++s]=k*c[i],v[s]=k*d[i];
	}
	for(i=1;i<M;i++) f[i]=-inf;
	for(i=1;i<=s;i++)
	{
		for(j=m;j>=w[i];j--)
		{
			if(f[j]<f[j-w[i]]+v[i])
				f[j]=f[j-w[i]]+v[i];
		}
	}
	printf("%d\n",ans+f[m]);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章