2010 NOIP提升組題解

機器翻譯

用隊列模擬題意便可node

#include<cstdio>
#include<iostream>
#include<cstring>

using namespace std; 
int n,m;
int head=0,tail=0;
int s[1100];
long long ans=0;
bool book[1100];
int main(){
	cin>>m>>n;memset(book,0,sizeof(book));
	for(int i=1;i<=n;++i){
		int a;cin>>a;
		if(book[a]==0){
			s[++tail]=a;book[a]=1;//入隊
			if(head+m<=tail)//出隊
				book[s[head++]]=0;
			++ans;
		}
	}
	cout<<ans<<endl;
	return 0;
}

烏龜棋

根據題意能夠嘗試爆搜
30ptsios

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,m;
long long ans=0; 
int a[390];
int b[6];
void dfs(int now,long long fs){
	if(now==n) {ans=max(ans,fs);return ;}
	for(int i=1;i<=4;++i){
		if(b[i]){
			b[i]--;
			dfs(now+i,fs+a[now+i]);
			b[i]++;
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;++i) cin>>a[i];
	for(int i=1;i<=m;++i) {	int u;cin>>u;++b[u];}
	dfs(1,a[1]); 
	cout<<ans<<endl;
	return 0;
}

正解應該用動態規劃
定義\(f[i][j][k][l]\)數組,到某個位置用了i張1牌,j張2牌,k張3牌,l張4牌
初始狀態:\(f[0][0][0][0]==val[1]\)(val數組記錄分數,val[1]爲第一張格子的分數)
末狀態:\(f[m_1][m_2][m_3][m_4](m_x爲第x張牌數量)\)
狀態轉移方程:
\(t=1*a+b*2+3*c+4*d(a,b,c,d分別爲用過的1,2,3,4牌,t爲下一步烏龜棋會到達的位置)\)
\(f[i][j][k][l]=min(f[i-1][j][k][l]+val[t],f[i][j][k][l])\)
\(f[i][j][k][l]=min(f[i][j-1][k][l]+val[t],f[i][j][k][l])\)
\(f[i][j][k][l]=min(f[i][j][k-1][l]+val[t],f[i][j][k][l])\)
\(f[i][j][k][l]=min(f[i][j][k][l-1]+val[t],f[i][j][k][l])\)數組

#include<cstdio>
#include<iostream> 
using namespace std;
int n,m;const int maxn=360;
int val[maxn];
int f[111][111][111][111];
int a=0,b=0,c=0,d=0;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i) scanf("%d",&val[i]);
	for(int i=1,x;i<=m;++i){
		scanf("%d",&x);
		if(x==1) ++a;if(x==2) ++b;if(x==3) ++c;if(x==4) ++d;
	}f[0][0][0][0]=val[1];
	for(int i=0;i<=a;++i)
		for(int j=0;j<=b;++j)
			for(int k=0;k<=c;++k)
				for(int l=0;l<=d;++l){
					int t=1*i+j*2+k*3+l*4+1;//烏龜棋下一步能走到那個位置 
					if(i!=0) f[i][j][k][l]=max(f[i-1][j][k][l]+val[t],f[i][j][k][l]);
					if(j!=0) f[i][j][k][l]=max(f[i][j-1][k][l]+val[t],f[i][j][k][l]);
					if(k!=0) f[i][j][k][l]=max(f[i][j][k-1][l]+val[t],f[i][j][k][l]);
					if(l!=0) f[i][j][k][l]=max(f[i][j][k][l-1]+val[t],f[i][j][k][l]);
				}
	printf("%d",f[a][b][c][d]);return 0;
}

關押罪犯

(文字量較大建議細讀題目)spa

影響力從大到小排成一個列表
市長只看第一件事
因此能夠很容易想到,儘量把最大值減少
那麼所以,(能夠貪心)儘可能依次拆分兩個怒氣值最大的兩人到兩個監獄,遇到兩人沒法拆開那麼就是正確答案(沒法拆開說明他們與其餘人有更大的c翻譯

  • 貪心證實
    假設拆分具備最大值的兩人拆到具備最小值,假如遇到兩人,能夠選擇不拆和拆
    若是不拆,此時c必定爲最大值,若是拆,則須要考慮兩種狀況
    拆了以後是否會到與以前拆過的人的監獄
    若是是,那麼就不拆,由於到了與以前拆過人的監獄的c必定大於當前c
    若是拆了不會到,那就可拆掉兩人,能夠減小影響力的最大值
    證畢
    (實力不夠,證實瑕疵不少,抱歉)

按影響力c排個序,用並查集記錄同一個監獄裏的人,又用一個數組記錄這個監獄裏的對立的人code

#include<cstdio>
#include<algorithm>

using namespace std;
int n,m;const int maxn=2e4+10;
int f[maxn],d[maxn];//f爲並查集,d記錄敵人
struct node{
	int u,v,w;
}e[maxn*10];
bool cmp(node a,node b){
	return a.w>b.w;
}
int find(int x){
	if(x!=f[x]) return f[x]=find(f[x]);
	return x;
}
bool check(int x,int y){
	return find(x)==find(y)?1:0;
}
void unite(int x,int y){
	f[find(x)]=find(y); 
} 
int main(){
	scanf("%d%d",&n,&m);for(int i=1;i<=n;++i)f[i]=i;
	for(int i=1;i<=m;++i) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	sort(e+1,e+1+m,cmp);
	for(int i=1;i<=m;++i){
		int u=e[i].u,v=e[i].v;
		if(check(u,v)){
			printf("%d",e[i].w);
			return 0;
		}
		else {
			if(!d[u]) d[u]=v;
			else unite(d[u],v); 
			if(!d[v]) d[v]=u;
			else unite(d[v],u);
		}
	} 
	printf("0");return 0;
}

引水入城

第一種作法

對因而否具備可行性
只須要dfs或bfs判斷一下就ok隊列

對於最少建造幾個蓄水廠
也能夠用爆搜搜出每一個點從上到下能覆蓋幾個線段,而後貪心線段覆蓋便可
至於時間複雜度卡常就能夠過去ci

第二種作法記憶化搜索+dp

記憶化搜索其實就是直接拿搜過的結果用
dp數組的是每一個點能到達的最左最右距離
因此要兩個數組
l[x][y]=min(l[i][j])(點i,j爲點x,y能到達的全部點)
l記錄最左端
r記錄最右端get

#include<cstdio>
#include<algorithm>
using namespace std;
int n,m;const int maxn=505;
bool vl[maxn][maxn];
struct node{
	int l,r;
	
}d[maxn][maxn];
int mp[maxn][maxn];int cnt=0;
int nt[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
inline int minn(int x,int y){
	return x<y?x:y;
}
inline int maxx(int x,int y){
	return x>y?x:y;
}
inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(c>'9' || c<'0'){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar();
	}return x*f;
}
inline int dfs(int x,int y){
	vl[x][y]=1;if(x==n) ++cnt;
	int nx,ny;
	for(int i=0;i<4;++i){
		nx=x+nt[i][0],ny=y+nt[i][1];
		if(nx<1 || ny<1 || nx>n || ny>m || mp[nx][ny]>=mp[x][y]) continue;
		if(!vl[nx][ny])dfs(nx,ny);
		d[x][y].l=minn(d[x][y].l,d[nx][ny].l);
		d[x][y].r=maxx(d[x][y].r,d[nx][ny].r);
	}
}
int main(){
	n=read();m=read(); 
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			mp[i][j]=read(),d[i][j].l=0x3f3f3f3f,d[i][j].r=0;
	for(int i=1;i<=m;++i)
		d[n][i].l=d[n][i].r=i;//dp邊界 
	for(int i=1;i<=m;++i) if(!vl[1][i]) dfs(1,i);
	if(cnt!=m){
		printf("0\n%d",m-cnt);return 0; //m-cnt爲不能建造的水利設施
	}int last=1;cnt=0;
	 while (last<=m){
        int maxr=0;
        for (int i=1;i<=m;i++)
            if (d[1][i].l<=last)
                maxr=max(maxr,d[1][i].r);
        cnt++;
        last=maxr+1;
    }puts("1");printf("%d",cnt);return 0;
}

ZFY AK IOIstring

相關文章
相關標籤/搜索