NOIP2015 提高組部分題解
阿新 • • 發佈:2018-12-12
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;
}