[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] 呦呦切克闹
根据定理如果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;
}