TEST2018.4.21(Noip2015提高组Day1)
为2019级lizw0520zzh的学生献上福利!!!
T1 神奇的幻方:
模拟题,很简单,按照题目描述进行模拟就行了,只是判断条件有点多,细心就行了。
用pos[i][0]表示i的行数,用pos[i][1]表示i的列数(这样好判断一些),mapp[][]记录幻方(mapp防止与map重名)。
代码(我一开始竟然调了好久?!):
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=45;
int mapp[N][N];
int pos[N*N][2];
int n;
void print() {
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++)
printf("%d ",mapp[i][j]);
printf("\n");
}
}
int main() {
//freopen("magic.in","r",stdin);
//freopen("magic.out","w",stdout);
scanf("%d",&n);
pos[1][0]=1;pos[1][1]=(n+1)/2;mapp[pos[1][0]][pos[1][1]]=1;
for(int i=2;i<=n*n;i++) {
if(pos[i-1][0]==1&&pos[i-1][1]!=n) pos[i][0]=n,pos[i][1]=pos[i-1][1]+1,mapp[pos[i][0]][pos[i][1]]=i;
else if(pos[i-1][1]==n&&pos[i-1][0]!=1) pos[i][1]=1,pos[i][0]=pos[i-1][0]-1,mapp[pos[i][0]][pos[i][1]]=i;
else if(pos[i-1][0]==1&&pos[i-1][1]==n) pos[i][1]=n,pos[i][0]=pos[i-1][0]+1,mapp[pos[i][0]][pos[i][1]]=i;
else if(pos[i-1][0]!=1&&pos[i-1][1]!=n) {
if(!mapp[pos[i-1][0]-1][pos[i-1][1]+1]) pos[i][0]=pos[i-1][0]-1,pos[i][1]=pos[i-1][1]+1;
else pos[i][0]=pos[i-1][0]+1,pos[i][1]=pos[i-1][1];
mapp[pos[i][0]][pos[i][1]]=i;
}
//print();
}
print();
return 0;
}
T2 信息传递:
2015的题真的很水。
核心就是找出最小环的长度。
这道题做法很多,我的思路是删去入度为0的点,然后直接dfs跑一遍就行。其他方法大家可以百度。
友情链接:水友gay周的博客(标准做法) 顺便说一下rancy是他的女朋友。
代码(宇宙最简):
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int N=200000+233;
int n,in[N],a[N];
bool vis[N];
bool del() {
bool re=false;
for(int i=1;i<=n;i++)
if(!in[i]&&!vis[i])
re=true,in[a[i]]--,a[i]=-1,vis[i]=true;
return re;
}
int dfs(int now,const int o) {
if(now==o&&vis[o]) return 0;
vis[now]=true;
return dfs(a[now],o)+1;
}
int main() {
//freopen("message.in","r",stdin);
//freopen("message.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d",a+i);
in[a[i]]++;
}
int ans=N+10;
while(del());
for(int i=1;i<=n;i++)
if(!vis[i]) ans=min(ans,dfs(i,i));
printf("%d",ans);
return 0;
}
大家有空可以尝试并查集做法。
T3 斗地主:
输了地主赢了人生的我(隔壁赢了地主输了人生的佘刀已经die了)。
就是模拟题(Noip2015模拟题真的多)
大家可以认真思考下最优策略,然后dfs顺子的出牌方式就行了,具体方法大家自行百度吧。
多组数据忘了初始化ans的我已经哭晕在厕所了。。。我的AK啊!
代码(绝对良心):
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxx(a,b) a>b?a:b
#define minn(a,b) a<b?a:b
using namespace std;
int T,n,a[20],ans;
void init() {
memset(a,0,sizeof(a));
for(int num,opt,i=1;i<=n;i++) {
scanf("%d%d",&num,&opt);
if(num==0) a[14]++;
if(num==1) a[12]++;
if(num==2) a[13]++;
if(num>=3) a[num-2]++;
}
}
void solve(int x) {
if(x>ans) return;
int s1,s2,s3,s4;
s1=s2=s3=s4=0;
for(int i=1;i<=14;i++) {
if(a[i]==1) s1++;
if(a[i]==2) s2++;
}
for(int i=1;i<=14;i++) {
if(a[i]==4) {
s4++;
if(s1>=2) s1-=2;
else if(s2>=2) s2-=2;
else if(s2>=1) s2-=1;
}
}
for(int i=1;i<=14;i++) {
if(a[i]==3) {
s3++;
if(s1>=1) s1-=1;
else if(s2>=1) s2-=1;
}
}
ans=min(ans,x+s1+s2+s3+s4);
for(int i=1;i<=8;i++) {
int j;
for(j=i;j<=12;j++) {
a[j]--;
if(a[j]<0) break;
if(j-i>=4) solve(x+1);
}
if(j==13) j--;
while(j>=i) a[j--]++;
}
for(int i=1;i<=10;i++) {
int j;
for(j=i;j<=12;j++) {
a[j]-=2;
if(a[j]<0) break;
if(j-i>=2) solve(x+1);
}
if(j==13) j--;
while(j>=i) a[j--]+=2;
}
for(int i=1;i<=11;i++) {
int j;
for(j=i;j<=12;j++) {
a[j]-=3;
if(a[j]<0) break;
if(j-i>=1) solve(x+1);
}
if(j==13) j--;
while(j>=i) a[j--]+=3;
}
}
int main() {
//freopen("landlords.in","r",stdin);
//freopen("landlords.out","w",stdout);
scanf("%d%d",&T,&n);
while(T--) {
ans=23;
init();
solve(0);
printf("%d\n",ans);
}
return 0;
}
最后祝大家早日AK!