NBUT Summer Contest-1题解报告


[A] 走走走走走啊走


再水不过的dp了,不过要注意一些细节,每个点可正可负,可选可不选。
状态方程是    t=max(dp[i][j-1],dp[i-1][j]),dp[i][j]=max(t+mat[i][j],t),初始化的时候,dp[0][0]也要选择大的,就因为开始没注意这个,wa了好多次。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>

using namespace std;
int mat[1500][1500];
int dp[1500][1500];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&mat[i][j]);
dp[0][0]=max(mat[0][0],0);
for(int i=1;i<n;i++)
dp[i][0]=max(dp[i-1][0]+mat[i][0],dp[i-1][0]);
for(int j=1;j<m;j++)
dp[0][j]=max(mat[0][j]+dp[0][j-1],dp[0][j-1]);
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
{
int t=max(dp[i-1][j],dp[i][j-1]);
dp[i][j]=max(t,t+mat[i][j]);
}

printf("%d\n",dp[n-1][m-1]);
}
return 0;
}

  • [B] 小明:你还认识我吗?


    给一个n,在1——n之间找三个数,使他们的最小公倍数最大。
    这么考虑,如果n是奇数,那么
    n   n-1   n-2分别是奇数,偶数,奇数 不存在有因子2的奇数,所以这是三者两两互质,他们的乘积就是最大的最小公倍数 。
    否则,如果n是偶数,那么

    1. n n-1 n-2,偶数,奇数,偶数,
    2.  n-1,n-2,n-3  奇数 ,偶数, 奇数
    3.n, n-1,n-3  偶数,奇数,奇数

    其他的显然不会更大,第三种要判断n是否是3的倍数。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>

using namespace std;

int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}

__int64 max (__int64 a,__int64 b ,__int64 c)
{
if(a>=b)
if(c>a)
return c;
else
return a;
else
{
if(c<b)
return b;
else
return c;
}

}

int main()
{
int n,t;
while(~scanf("%d",&t))
{
while(t--)
{
scanf("%d",&n);
if(n>=3)
{
if(n%2)
printf("%I64d\n",(__int64)n*(n-1)*(n-2));
else
{
__int64 a=(__int64)(n-1)*(n-2)*(n-3),b;
if(n%3==0)
b=(__int64)n*(n-1)*(n-3)/3;
else
b=(__int64)n*(n-1)*(n-3);
__int64 c=(__int64)n*(n-1)*(n-2)/2;
__int64 maxs=max(a,b,c);
printf("%I64d\n",maxs);
}
}
else
printf("%d\n",n);
}
}
return 0;
}


    • [C] Brave Sword

      给你一个数组,让你找出其中两个只出现一次的数。
      既然有两个不同的数,那么所有数的异或值一定不为0,换句话说,这个异或值存在某一位是1,设这两个只出现一次的数为A,B,那么A和B在那一位上的值一定是不同的,所以可以按此来划分数组。

      每一份中相同的数异或后是0,那么每一份的异或值就是要找的数。

      #include<stdio.h>  

      int allnum[1000000];
      int main()
      {
      int n;
      while(~scanf("%d",&n))
      {
      int i,j,s=0;
      for(i=0;i<n;i++)
      {
      scanf("%d",&allnum[i]);
      s^=allnum[i];
      }
      int first;
      //寻找xor最后一位为1的位置
      for(i=0;i<32;i++)
      {
      if((s>>i)%2==1)
      {
      first=i;
      break;
      }
      }
      int one=0,another=0;
      for(i=0;i<n;i++)
      {
      if((allnum[i]>>first)%2==1)
      one^=allnum[i];
      else
      another^=allnum[i];
      }
      printf("%d %d\n",one<another?one:another,one>another?one:another);
      }
      return 0;
      }



      • [1569] |HELLO - WORLD|

        本题的话,先把数组排序,找出中间位置,将x放置即可,放在中间位置,不会有极端大的数出现,例如把x放在最左端,那么最右端-最左端可能会很大,所以,放在中间位置是最好的方案。
        注意精度。。。。

        #include<stdio.h>
        #include<string.h>
        #include<iostream>
        #include<algorithm>
        #include<map>
        #include<vector>
        #include<queue>
        #include<cmath>

        using namespace std;

        int cmp(double a,double b)
        {
        return a<b;
        }

        double pos[10010];

        int main()
        {
        int n,t,p=0;
        while(~scanf("%d",&t))
        {
        for(int k=1;k<=t;k++)
        {
        if(p!=0)
        printf("\n");
        else
        p=1;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        scanf("%lf",&pos[i]);
        sort(pos+1,pos+1+n,cmp);
        double x1=pos[n/2],sum1=0;
        double x2=pos[(n/2)+1],sum2=0;
        for(int i=1; i<=n; i++)
        sum1+=fabs(x1-pos[i]);
        for(int i=1; i<=n; i++)
        sum2+=fabs(x2-pos[i]);
        printf("Case %d:",k);
        if(sum2 - sum1 > 1e-6)
        printf("%f %f\n",x1,sum1);
        else if(sum1 - sum2 > 1e-6)
        printf("%f %f\n",x2,sum2);
        else
        printf("%f %f\n",x1,sum1);
        }
        }
        return 0;
        }


        • [E] 呦呦切克闹


        KMP的题,求出next模式函数值
        根据定理如果str存在循环子串,当且仅当len可以被(len-next[len])整除。
        参考了其他博客给出的证明:
          我们令str=A1A2A3A4A5A6A7A8,设next[8]=6,此时按上式,循环子串是8-6=2也就是A1A2,再根据next[8]=6,得到  A1A2A3A4A5A6==A3A4A5A6A7A8,那么就有A1A2==A3A4,A3A4==A5A6,A5A6==A7A8,显然有A1A2是循环子串。

        #include<stdio.h>
        #include<string.h>
        #include<iostream>
        #include<algorithm>
        #include<map>
        #include<vector>
        #include<queue>
        #include<math.h>

        using namespace std;

        int next[100010];

        char str[100010];

        void get_next()
        {
        int j=0,k=-1;
        next[0]=-1;
        while(str[j]!='\0')
        {
        if(k==-1 || str[k]==str[j])
        {
        j++;
        k++;
        if(str[j]!=str[k])//前面k个相同,但是这两个不同,回溯到k
        next[j]=k;
        else
        next[j]=next[k];
        }
        else
        {
        k=next[k];//回滚到上一个匹配点
        }
        }
        }


        int main()
        {
        while(~scanf("%s",str))
        {
        get_next();
        int len=strlen(str);
        if((len)/(len-next[len])>=2)//段数>=2
        printf("Win\n");
        else
        printf("Lost\n");
        }
        return 0;
        }


你可能感兴趣的:(NBUT Summer Contest-1题解报告)