NOIP2017赛前模拟(5):总结

题目:

1.刮刮卡

  已知n(n<=1000000)张刮刮卡按顺序排列,刮开可以获得B元现金和B个积分,购买刮刮卡需要A元,某人若按照顺序刮开的话··当B的总和小于A时便会停止刮卡(即花出去的钱多余赢得的钱),现在我们可以将前k张按原来的顺序放到后面去···问k取多少时这个人可以获得多少积分?

2.矩阵

  给出一个n行m阵的矩阵(n,m<=100),问如果从中选出K个互不重叠的非空子矩阵使得子矩阵的和最大

3.裁剪表格

  给出n行m列的矩阵··(n,m<=1000)和q(q<=10000)次操作··每次操作交换两个互不重合的子矩阵···输出最后的矩阵

题解:

1.最大子串和

  略

  代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e6+5;
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<'0'||c>'9';c=getchar());
  for(;c<='9'&&c>='0';c=getchar())  f=(f<<3)+(f<<1)+c-'0'; 
  return f;
} 
int num[N*2],a[N],b[N*2],n;
int main()
{
  //freopen("rock.in","r",stdin);
  //freopen("rock.out","w",stdout);
  n=R();int ans=0,sum1=0,maxx=0,sum2=0;
  for(int i=1;i<=n;i++)  b[i]=b[i+n]=R();
  for(int i=1;i<=n;i++)  a[i]=R(),num[i]=num[i+n]=b[i]-a[i];
  int Head=1;
  while(Head<=n)
  {
    if(num[Head]<0)  {Head++;continue;}
    int Tail=Head;sum1=0,sum2=0;
    while(Tail-Head+1<=n)
    {
      sum1+=num[Tail];
      sum2+=b[Tail];
      if(sum2>maxx) 
        maxx=sum2,ans=Head-1;
      if(Tail-Head+2<=n&&sum1+num[Tail+1]>=0)  
        Tail++;
      else break;
    }  
    Head=Tail+1;
  }
  cout<<ans<<endl;
  return 0;
}

 

2.dp

  用f[i][j][k]表示第一列取了前i个,第二列取了前j个且组成了k个子矩阵的最小值,具体转移方程看代码吧··

  md考试时忘记初始化-inf了····下次一定要注意··

  代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=105;
const int K=15;
const long long inf=1e+18;
int n,m,k,num[N],map[N][5];
long long f1[N],sum[5][N],temp[N],f2[N][N][K];
inline int R()
{
  char c;int f=0,i=1;
  for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
  if(c=='-')  i=-1,c=getchar();
  for(;c<='9'&&c>='0';c=getchar())  f=(f<<3)+(f<<1)+c-'0';
  return f*i;
}
int main()
{
  //freopen("matrix.in","r",stdin);
 // freopen("matrix.out","w",stdout);
  n=R(),m=R(),k=R();
  if(m==1)
  {
    for(int i=1;i<=n;i++)  num[i]=R();
    memset(f1,-10,sizeof(f1));
    f1[0]=0;
    for(int i=1;i<=k;i++)
    {  
      for(int j=i;j<=n;j++) 
      {
        if(j==i)  f1[j]=temp[j-1]+num[j];
        else f1[j]=max(f1[j-1]+num[j],temp[j-1]+num[j]);
      }
      for(int j=i;j<=n;j++)
      {
        if(j==i)  temp[j]=f1[j];
        else temp[j]=max(temp[j-1],f1[j]);
      }
    }
    long long ans=-inf;
    for(int i=k;i<=n;i++)  ans=max(ans,f1[i]);
    cout<<ans<<endl;
  }
  else
  {
    memset(f2,-10,sizeof(f2));
    long long tot=0;bool flag=true;
    for(int i=1;i<=n;i++)  
      for(int j=1;j<=2;j++)  
      {  
        map[i][j]=R();tot+=map[i][j];
        if(map[i][j]<0)  flag=false;
        sum[j][i]=sum[j][i-1]+map[i][j];
      }
    if(flag)  
    {
      cout<<tot<<endl;return 0;
    }
    for(int i=0;i<=n;i++)
      for(int j=0;j<=n;j++)  f2[i][j][0]=0;
    for(int i=1;i<=k;i++)
      for(int j=1;j<=n;j++)  //第一列 
        for(int l=1;l<=n;l++)  //第二列 
        { 
          f2[j][l][i]=max(f2[j-1][l][i],f2[j][l-1][i]);
          for(int p=0;p<j;p++) 
            f2[j][l][i]=max(f2[j][l][i],f2[p][l][i-1]+sum[1][j]-sum[1][p]);
          for(int p=0;p<l;p++)
            f2[j][l][i]=max(f2[j][l][i],f2[j][p][i-1]+sum[2][l]-sum[2][p]);
          if(l==j)
          for(int p=0;p<j;p++)
            f2[j][l][i]=max(f2[j][l][i],f2[p][p][i-1]+sum[2][l]-sum[2][p]+sum[1][j]-sum[1][p]);
        }
    cout<<f2[n][n][k]<<endl;
  }
  return 0;
}

 

3.链表

  看了题解后发现链表是一个神奇的东西··另外也发现register配上for循环的优化效果的显著···

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=1005;
int n,m,q,pos[N][N],ri[N*N],down[N*N],val[N*N],tot;
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<'0'||c>'9';c=getchar());
  for(;c<='9'&&c>='0';c=getchar())  f=(f<<3)+(f<<1)+c-'0';
  return f;
}
inline int find(int x,int y)
{
  int t=pos[0][0];
  for(int i=1;i<=x;i++)  
    t=down[t]; 
  for(int i=1;i<=y;i++)
    t=ri[t];
  return t;
}
int main()
{
  //freopen("a.in","r",stdin);
  n=R(),m=R(),q=R();
  for(register int i=1;i<=n;i++)
    for(register int j=1;j<=m;j++)   
      val[pos[i][j]=++tot]=R();
  for(register int i=0;i<=m+1;i++)
    pos[0][i]=++tot,pos[n+1][i]=++tot;
  for(register int i=1;i<=n;i++)
    pos[i][0]=++tot,pos[i][m+1]=tot;
  for(register int i=0;i<=n;i++)
    for(register int j=0;j<=m;j++)
    { 
      ri[pos[i][j]]=pos[i][j+1];
      down[pos[i][j]]=pos[i+1][j];
    }
  while(q--)
  {
    int r1=R(),c1=R(),r2=R(),c2=R(),h=R(),w=R();
    register int t1=find(r1-1,c1-1),t2=find(r2-1,c2-1),T1,T2,i;
    for(T1=t1,T2=t2,i=1;i<=h;i++)
      swap(ri[T1=down[T1]],ri[T2=down[T2]]);
    for(i=1;i<=w;i++)
      swap(down[T1=ri[T1]],down[T2=ri[T2]]);
    for(T1=t1,T2=t2,i=1;i<=w;i++)
      swap(down[T1=ri[T1]],down[T2=ri[T2]]);
    for(i=1;i<=h;i++) 
      swap(ri[T1=down[T1]],ri[T2=down[T2]]);
  }
  int p=pos[0][0];
  for(register int i=1;i<=n;i++)
  {
    p=down[p];
    for(register int j=1,t=p;j<=m;j++)
      cout<<val[t=ri[t]]<<" ";
    cout<<endl;
  }
  return 0;
}

 

posted @ 2017-10-20 18:00  AseanA  阅读(165)  评论(0编辑  收藏  举报