1. 程式人生 > >NOIP2015 提高組部分題解

NOIP2015 提高組部分題解

Day1_1_神奇的幻方

https://www.luogu.org/problemnew/show/P2615

/*
*題目摘要:規律:i+1在i的右上方,如果已經有數了,就填在i的下方 
*1. 若 (N-1) 在第一行但不在最後一列,則將 N 填在最後一行, (N-1) 所在列的右一列; 
*2. 若 (N-1) 在最後一列但不在第一行,則將 N 填在第一列,(N-1) 所在行的上一行; 
*3. 若 (N-1) 在第一行最後一列,則將 N 填在 (N-1) 的正下方; 
*4. 若 (N-1) 既不在第一行,也不在最後一列,如果 (N-1) 的右上方還未填數,
*則將 K填在(N-1)的右上方,否則將 N 填在 (N-1) 的正下方。 
*/
#include<bits/stdc++.h> using namespace std; int n,a[40][40]; int main() { cin>>n; int nx=1,ny=n/2+1; a[nx][ny]=1; for (int i=2;i<=n*n;i++) { int tx,ty; if (nx==1) { if (ny!=n) { tx=n; ty=ny+1; } else { tx=nx+1; ty=ny; } } else { if (ny==n){tx=nx-1;ty=1;} else
{ tx=nx-1; ty=ny+1; if (a[tx][ty]) { tx=nx+1; ty=ny; } } } a[tx][ty]=i; nx=tx; ny=ty; } for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) cout<<a[i][j]<<' '; cout<<endl; } return 0; }

Day1_2_資訊傳遞

https://www.luogu.org/problemnew/show/P2661

#include<bits/stdc++.h>
using namespace std;
int n, now, ans=0x7fffffff, a[210000], u[210000], v[210000];
inline int read()
{
	int f=1,num=0;
	char ch=getchar();
	while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
	while (ch>='0'&&ch<='9') { num=(num<<1)+(num<<3)+ch-'0'; ch=getchar(); }
	return num*f;
}
void dfs(int x,int z)
{
	if (v[x]!=0)
	{
		if (u[x]==now) ans=min(ans,z-v[x]);
		return ;
	}
	u[x]=now,v[x]=z,dfs(a[x],z+1);
	return ;
}
int main()
{
	n=read();
	for (int i=1;i<=n;i++)
		a[i]=read();
	for (int i=1;i<=n;i++)
	{
		now=i;
		if (v[i]==0) u[i]=now,v[i]=1,dfs(a[i],2);
	}
	cout<<ans<<endl;
	return 0;
}

Day1_3_鬥地主

https://www.luogu.org/problemnew/show/P2668

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
int hand[25];
int sum[25];
int ans;
int unline()
{
	memset(sum,0,sizeof(sum));
	for (int i=0;i<=13;i++)
		sum[hand[i]]++;
    int tot=0;                                  
    while(sum[4]&&sum[2]>1)  sum[4]--,sum[2]-=2,tot++;      
    while(sum[4]&&sum[1]>1) sum[4]--,sum[1]-=2,tot++;
    while(sum[4]&&sum[2]) sum[4]--,sum[2]--,tot++;
    while(sum[3]&&sum[2]) sum[3]--,sum[2]--,tot++;
    while(sum[3]&&sum[1]) sum[3]--,sum[1]--,tot++;
    return tot+sum[1]+sum[2]+sum[3]+sum[4]; 
}
void dfs(int dep)
{
	if (dep>=ans)return;
	int tmp=unline();
	if (tmp+dep<ans)ans=tmp+dep;
	for (int i=2;i<=13;i++) 
	{                            
        int j=i;
		while(hand[j]>=3) j++;
        if(j-i>=2) 
		{
            for (int j2=i+1;j2<=j-1;j2++) 
			{
                for (int k=i;k<=j2;k++) hand[k]-=3;
                dfs(dep+1);
                for (int k=i;k<=j2;k++) hand[k]+=3;
		    }
	    }
    }
    for (int i=2;i<=13;i++) 
	{                                
        int j=i;
		while(hand[j]>=2) j++;
        if(j-i>=3) 
		{
            for (int j2=i+2;j2<=j-1;j2++) 
			{
                for (int k=i;k<=j2;k++) hand[k]-=2;
                dfs(dep+1);
                for (int k=i;k<=j2;k++) hand[k]+=2;
		    }
	    }
    }
    for (int i=2;i<=13;i++) 
	{                             
        int j=i;
		while(hand[j]>=1) j++;
        if(j-i>=5) 
		{
            for (int j2=i+4;j2<=j-1;j2++) 
			{
                for (int k=i;k<=j2;k++) hand[k]--;
                dfs(dep+1);
                for (int k=i;k<=j2;k++) hand[k]++;
		    }
	    }
    }
}
int main()
{
	//freopen("landlords.in","r",stdin);
	//freopen("landlords.out","w",stdout);
	int T;
	scanf("%d%d",&T,&n);
	while (T--)
	{
		memset(hand,0,sizeof(hand));
		for (int i=1;i<=n;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			if(x==1) x=13; 
			else if(x) x--;
            hand[x]++;
		}
		ans=0x7f7f7f7f;
		dfs(0);
		printf("%d\n",ans);
	}
	return 0;
}
/*#include<bits/stdc++.h>
#define up 15
using namespace std;
int cnt[up],fi[up][up][up][up],ans;
int idx(int x,int y)
{
    if (!x) return 14;
    if (x==1||x==2) return x+11;
    return x-2;
}
void dfs(int dep,int ci)
{
    int i,j,k;
    if (ci>=ans) return;
    if (dep==1)
	{//三順
        for (i=1;i<=12;++i)
		{
            if (cnt[i]<3) continue;
            j=i;
			while(j<12&&cnt[j+1]>=3)
				++j;
            if (j-i+1>=2)
			{
                for (k=j;k>=i;--k)
					cnt[k]-=3;
                k=3*(j-i+1);
                while(j-i+1>=2)
				{
                    dfs(1,ci+1);
					k-=3,cnt[j]+=3,--j;
                }
				for (k=j;k>=i;--k) 
					cnt[k]+=3;
            }
        }
		dfs(2,ci);
		return;
    }
	if (dep==2)
	{//雙順
        for (i=1;i<=12;++i)
		{
            if (cnt[i]<2) continue;
            j=i;
			while(j<12&&cnt[j+1]>=2)
				++j;
            if (j-i+1>=3)
			{
                for (k=j;k>=i;--k)
					cnt[k]-=2;
                k=2*(j-i+1);
                while(j-i+1>=3)
				{
                    dfs(2,ci+1);
					k-=2,cnt[j]+=2,--j;
                }
				for (k=j;k>=i;--k)
					cnt[k]+=2;
            }
        }
		dfs(3,ci);
		return;
    }
	if (dep==3)
	{//單順
        for (i=1;i<=12;++i)
		{
            if (!cnt[i]) continue;
            j=i;
			while(j<12&&cnt[j+1])
				++j;
            if (j-i+1>=5)
			{
                for (k=j;k>=i;--k)
					cnt[k]-=1;
                k=j-i+1;
                while(j-i+1>=5)
				{
                    dfs(3,ci+1);
					k-=1,cnt[j]+=1,--j;				
                }
				for (k=j;k>=i;--k)
					cnt[k]+=1;
            }
        }
		dfs(4,ci);
		return;
    }
	int a,b,c,d,t;
	a=b=c=d=0;//dp 
    memset(fi,127/3,sizeof(fi));
    for (i=1;i<up;++i)
	{
        if (cnt[i]==4) ++d;
        if (cnt[i]==3) ++c;
        if (cnt[i]==2) ++b;
        if (cnt[i]==1) ++a;
    }
	fi[0][0][0][0]=0;
    for (i=0;i<=a;++i)
    	for (j=0;j<=b;++j)
    		for (k=0;k<=c;++k)
        		for (t=0;t<=d;++t)
				{
            		if (t)
					{
                		fi[i][j][k][t]=min(fi[i][j][k][t],fi[i][j][k][t-1]+1);
                		if (j) fi[i][j][k][t]=min(fi[i][j][k][t],fi[i][j-1][k][t-1]+1);
                		if (j>=2) fi[i][j][k][t]=min(fi[i][j][k][t],fi[i][j-2][k][t-1]+1);
                		if (t>=2) fi[i][j][k][t]=min(fi[i][j][k][t],fi[i][j][k][t-2]+1);
                		if (i>=2) fi[i][j][k][t]=min(fi[i][j][k][t],fi[i-2][j][k][t-1]+1);
            		}
					if (k)
					{
                		fi[i][j][k][t]=min(fi[i][j][k][t],fi[i][j][k-1][t]+1);
                		if (i) fi[i][j][k][t]=min(fi[i][j][k][t],fi[i-1][j][k-1][t]+1);
                		if (j) fi[i][j][k][t]=min(fi[i][j][k][t],fi[i][j-1][k-1][t]+1);
            		}
					if (j) fi[i][j][k][t]=min(fi[i][j][k][t],fi[i][j-1][k][t]+1);
            		if (i) fi[i][j][k][t]=min(fi[i][j][k][t],fi[i-1][j][k][t]+1);
        		}
    ans=min(ans,ci+fi[a][b][c][d]);
}
int main()
{
    int t,n,x,y;
	scanf("%d%d",&t,&n);
    while(t--)
	{
        memset(cnt,0,sizeof(cnt));
        for (int i=1;i<=n;++i)
		{
            scanf("%d%d",&x,&y);
            ++cnt[idx(x,y)];
        }
		ans=n;
		dfs(1,0);
        printf("%d\n",ans);
    }
    return 0;
}*/

Day2_1_跳石頭

https://www.luogu.org/problemnew/show/P2678

#include<bits/stdc++.h>
using namespace std;
int l, n, m, di[51000], ans;
inline int read()
{
	int f=1,num=0;
	char ch=getchar();
	while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
	while (ch>='0'&&ch<='9') { num=(num<<1)+(num<<3)+ch-'0'; ch=getchar(); }
	return num*f;
}
bool check(int k)
{
	int last=0;//上一塊石頭距起點的位置
	int move=0;
	for (int i=1;i<=n;i++)
	{
		if (di[i]-last<k)//如果這兩塊石頭相距小於當前值,
			move++;//就要把這塊石頭移走
		else last=di[i];
	}
	if (move>m) return 0;//移走的數目多於m,說明答案取大了 
    else return 1;//反之答案取小了 
}
int main()
{
	l=read(),n=read(),m=read();
	for (int i=1;i<=n;i++)
		di[i]=read();
	di[n+1]=l;//終點。
	int left=0,right=l;//二分。
	while (left<=right)
	{
		int mid=(left+right)>>1;
		if (check(mid)) left=mid+1;//如果可以讓所有的跳躍距離都大於mid,下一步在[mid+1,r]中再二分 
		else right=mid-1;//反之在[l,mid-1]中二分。
	}
	cout<<right<<endl;
	return 0;
}