ACM-ICPC 2017 南宁赛区现场赛 L,I,H题
L题:
题目链接:https://nanti.jisuanke.com/t/A1541
题意:找到最小的n且大于L的数字满足2*m(m+1)=n*(n+1);
思路:打表找规律,我脑子不够用,没找出来;规律是:ans[i]=ans[i-1]*6-ans[i-2]+2;
然后再大数模拟下就可以了;
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<string> #include<queue> #include<cstdlib> using namespace std; typedef long long ll; int a[2005][2005],b[2005]; char c[2000]; int main() { b[0]=1; b[1]=2; a[0][0]=3; a[1][0]=0; a[1][1]=2; for(int i=2; i<=300; i++) { for(int j=0; j<b[i-1]; j++) a[i][j]=a[i-1][j]*6; a[i][0]+=2; for(int j=0; j<b[i-2]; j++) a[i][j]-=a[i-2][j]; int v=0; for(int j=0; j<b[i-1]; j++) { if(v==1) { if(a[i][j]<=0) a[i][j]+=9; else { a[i][j]--; v=0; } } else { if(a[i][j]<0) { a[i][j]+=10; v=1; } } } for(int j=0; j<b[i-1]; j++) { a[i][j+1]=a[i][j+1]+a[i][j]/10; a[i][j]=a[i][j]%10; } if(a[i][b[i-1]]>0) b[i]=b[i-1]+1; else b[i]=b[i-1]; } int t; scanf("%d",&t); while(t--) { scanf("%s",c); int n=strlen(c); int k=lower_bound(b,b+300,n)-b; for(int i=k; i<=300; i++) { if(b[i]>n) { for(int j=b[i]-1; j>=0; j--) printf("%d",a[i][j]); printf("\n"); break; } int v=1; for(int j=n-1; j>=0; j--) { if(a[i][j]>c[n-j-1]-'0') break; else if(a[i][j]<c[n-j-1]-'0') { v=0; break; } } if(v==1) { for(int j=b[i]-1; j>=0; j--) printf("%d",a[i][j]); printf("\n"); break; } } } return 0; }
I题:
题目链接:https://nanti.jisuanke.com/t/A1538
题意:有4*4的矩阵,两个人玩游戏,先手从其中任选2*2的矩阵,然后将所选矩阵逆时针转一下,后手从其中任选2*2的矩阵,然后将所选矩阵逆时针转一下,每一轮先手的任 务是让两人的和最大,后手的任务是让两人的和最小,进行k轮,问k轮两人所选的矩阵的所有加和是多少。
思路:k不是很大,而且后面的选择不会影响到前面的选择,所以可以dfs回溯求值
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<string> #include<queue> #include<cstdlib> using namespace std; typedef long long ll; int inf=99999999; int a[5][5]; int n; void L(int x,int y) { int p=a[x][y]; a[x][y]=a[x][y+1]; a[x][y+1]=a[x+1][y+1]; a[x+1][y+1]=a[x+1][y]; a[x+1][y]=p; } void R(int x,int y) { int p=a[x][y]; a[x][y]=a[x+1][y]; a[x+1][y]=a[x+1][y+1]; a[x+1][y+1]=a[x][y+1]; a[x][y+1]=p; } int fun(int x,int y) { return a[x][y]+a[x][y+1]+a[x+1][y]+a[x+1][y+1]; } int dfs(int x) { if(x==2*n) { int mi=inf; for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) mi=min(mi,fun(i,j)); return mi; } if(x%2==1) { int ma=0; for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) { L(i,j); int ans=fun(i,j)+dfs(x+1); R(i,j); ma=max(ma,ans); } return ma; } int mi=inf; for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) { L(i,j); int ans=fun(i,j)+dfs(x+1); R(i,j); mi=min(mi,ans); } return mi; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) scanf("%d",&a[i][j]); printf("%d\n",dfs(1)); } }
H题:
题目链接:https://nanti.jisuanke.com/t/A1537
题意:给出n*m的字符型矩阵,'.'表示不存在细胞,’#‘表示存在。若当前活着的细胞旁边(8联通)存在的活着的细胞数小于2,则当前细胞死亡;
若当前活着的细胞旁边存在的活着的细胞数等于2,则当前细胞能够进行到下一次的分裂;
若当前细胞(死细胞或活细胞)旁边存在的活着的细胞数等于3,则当前位置的细胞变活;
若当前的细胞旁边存在的活着的细胞数大于3,则当前细胞死亡;
思路:暴力模拟就可以了,每次更新活细胞在哪个范围里,然后暴力就可以了;
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<string> #include<queue> #include<cstdlib> using namespace std; typedef long long ll; char cc[10]; int a[800][800],b[800][800]; int fun(int x,int y) { int s=0; for(int i=x-1;i<=x+1;i++) for(int j=y-1;j<=y+1;j++) { if(i==x&&j==y) continue; if(a[i][j]==1) s++; } return s; } int main() { int t; scanf("%d",&t); while(t--) { memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); int n,m; scanf("%d %d",&n,&m); int l=400,r=400+n; int ll=400,rr=400+m; int l1=l,r1=r; int ll1=ll,rr1=rr; int ma=0,p=0; for(int i=0;i<n;i++) { scanf("%s",cc); for(int j=0;j<m;j++) { if(cc[j]=='#') { a[i+400][j+400]=1; b[i+400][j+400]=1; ma++; } } } for(int k=1;k<=321;k++) { int sum=0; for(int i=l-1;i<=r+1;i++) for(int j=ll-1;j<=rr+1;j++) { int x=fun(i,j); if(x<2||x>3) b[i][j]=0; else if(x==3) b[i][j]=1; if(b[i][j]==1) { sum++; l1=min(l1,i); r1=max(r1,i); ll1=min(ll1,j); rr1=max(rr1,j); } } if(sum>ma) { ma=sum; p=k; } if(k==321) printf("%d %d %d\n",p,ma,sum); for(int i=l-1;i<=r+1;i++) for(int j=ll-1;j<=rr+1;j++) a[i][j]=b[i][j]; l=l1; r=r1; ll=ll1; rr=rr1; } } return 0; }