A1046 Shortest Distance
读题说明
题目理解本身不困难,英文也容易看懂,一般的解法容易想到,与距离无关,其实就是一个累加问题,因为路径是规划定的,只有左右结点相邻之间有一个距离,所以无需存储结点,只需要按顺序存储距离就可,然后根据顺/逆时针算出两种距离,(sum-顺=逆)
#include<cstdio>
using namespace std;
int main()
{
int N;
int sum=0;
int d[100005];
int re[10002];
//dis[100005];
int m;
scanf("%d ",&m);
for(int i=1;i<=m;i++)
{
scanf("%d ",&d[i]);
sum+=d[i];
//dis[i]=sum;
}
scanf("%d",&N);
for(int j=0;j<N;j++)
{
int pi,pj;
int dp=0,dn=0;
scanf("%d %d",&pi,&pj);
if(pi>pj)
{int temp;
temp=pi;
pi=pj;
pj=temp;
}
for(int i=pi;i<=pj;i++)
{
dp+=d[i];
}
//这个for循环去掉
//dp=dis[pj-1]-dis[pi-1];
dn=sum-dp;
re[j]=dn>=dp?dp:dn;
}
for(int i=0;i<N;i++)
{
printf("%d",re[i]);
if(i!=N-1)
printf("\n");
}
}
结果是部分AC,仔细一看是时间复杂度问题。
极端情况下,中间的两次for循环最大复杂度达到9次方,200ms不行,所以这两个for必须去掉一个。
时间复杂度解决办法
放弃最开始的顺逆时针每次输入一个点计算法,其实有一些值是可以复用的,使用一个数组保存从第一个结点到当前结点的距离之和,之后使用两个差值替换。代码如上。
感悟
题目虽然易懂,但是要注意时间复杂度的限制。
B1010 一元多项式求导
读题说明
这道题目本身不难,但是需要注意一些点。
- 如何停止输入(设置输入停止条件)
- 当求导为0的零多项式需要输出0 0
AC代码
#include<cstdio>
using namespace std;
int main()
{
int num[10];//根据测试,这道题目的数组最大值为10
int m=0;
for(int i=1;scanf("%d %d",&num[i],&num[i+1])!=EOF;i+=2)//使用scanf的返回值!=EOF作为读入结束标记
{
m=i+1;
}
for(int i=1;i<=m;i+=2)
{
if(!num[i+1])
{
m-=2;
break;
}
num[i]*=num[i+1];
num[i+1]-=1;
}
if(!num[2]||!num[1]) printf("0 0");//这一步就是零多项式
else{
for(int i=1;i<=m;i++)
{
printf("%d",num[i]);
if(i!=m) printf(" ");
}
}
}
A1065 A+B and C (64bit)
第一次写的代码,部分AC
#include<cstdio>
using namespace std;
typedef long long LL;
int main()
{
int T;
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
bool p=false;
LL A,B,C;
scanf("%lld %lld %lld",&A,&B,&C);
LL temp=A+B;
if(A>0&&B>0&&temp<0||temp>C) p=true;
/*if(A>0 && B>0 && temp<0) p=true;
else if(A<0 && B<0 && temp>=0) p=false;
else if(temp>C) p=true;
else p=false;*/
// /**/内为修改后AC代码
if(p) printf("Case #%d: true",i);
else printf("Case #%d: false",i);
if(i!=T) printf("\n");
}
}
部分AC原因探求
不妨假设此时A+B已经溢出,并且是正溢出,那if的前一个判断条件为true可以成立,但是如果此时是负溢出,第一个条件不成立,接着判断temp>C,未必成立(temp取值是[0,2^63)),假如成立,那么p=true,显然不对,因为此时负溢出,意味着A+B<C。
所以判断的基本原则,应该是先排除溢出的情况,然后再讨论正常情况,在未判断完溢出情况前不可判断正常情况