总结
- 学习了accumulate的一些知识,如返回值类型,自定义求和函数。
- 双指针的一种写法:先for再while
- 写计算几何题一定要冷静的推公式,尽量用便于debug的写法去写。
- 数位dp的有关内容见之后的学习笔记。
1036A. Function Height
k除以n,取上整,(k+n-1)/n
1036B. Diagonal Walking v.2 结论
1e4个询问,每次给出第一象限的一个整点,问k步从原点走到(n,m),最多可以走几次对角。
如果k<max(n,m),走不到,输出-1。否则先斜走到和目标点同一直线处,再分类讨论。
记k为剩余步数,d为直线距离。
当k为偶数,d为偶数时,答案加k.
当k为奇数,d为偶数时,答案加k-2(注意可能出现无解情况).
当k为偶数,d为奇数时,答案加k-1.
当k为奇数,d为奇数时,答案加k-1.
1036C. Classy Numbers 数位dp
定义好看数字为含有不超过3个非0数字位的数字,1e4个询问,每次问两个数(1e18)之间好看数字的个数。
请看数位dp学习笔记
1036D. Vasya and Arrays 双指针
给出两个数组,每次操作可以选择数组中的连续一段,将它们替换为它们的和。问这两个数组能否操作成一样的,如果能,最终的数组最长可以有多长。
如果两个数组之和相同,则可以,否则不行。
从头开始双指针扫描,每有一段相同就截取下来并且给答案加一。
我的双指针写法有问题,最开始扫不到最后一个地方。
后来换了一种写法,对
进行外层for循环,对
进行内层while循环,每次第二个数组当前和比第一个数组大时就更新答案。
注意accumulate返回值的类型是第三个参数的类型,而不是容器类型。
accumulate可以添加第四个参数lambda表示行为,lambda函数的第一个参数类型应与accumulate的第三个参数相同,第二个参数类型应与元素类型相同。
ll A[M],B[M];
int main(void)
{
#ifdef _LITTLEFALL_
freopen("in.txt","r",stdin);
#endif
int n = read();
for(int i=0;i<n;++i) A[i] = read();;
int m = read();
for(int i=0;i<m;i++) B[i] = read();
if(accumulate(A,A+n,0ll) != accumulate(B,B+m,0ll))
return !printf("-1\n");
int ans = 0;
ll sumA=0,sumB=0;
for(int i=0,j=0;i<n;i++)
{
sumA += A[i];
while(sumB < sumA)
sumB += B[j++];
if(sumA == sumB)
ans++;
}
printf("%d\n",ans );
return 0;
}
1036E. Covered Points 计算几何
给出n(1000)个各不同线的线段,线段的端点都在格点上,求这些线段一共覆盖了多少格点。
计算每个线段覆盖了多少个格点,再减去所有在格点上的交点就是答案。
每个线段覆盖的格点数目是
。为了避免交点重复,用每一条线段与之前的线段求交,把交点放在set里,求完一轮后set的大小就是添加这条线段新产生的交点数。
为了便于判别交点是否在线段上,我让x1<x2,y1<y2,这样产生的结果是错误的,因为可能改变了斜率,应当只换一个,同步另一个。
struct Line
{
ll x1,y1,x2,y2;
}line[M];
set<pair<ll,ll>> st;
void intersection(int l1, int l2)
{
ll x1 = line[l1].x1, x2 = line[l1].x2, x3 = line[l2].x1, x4 = line[l2].x2;
ll y1 = line[l1].y1, y2 = line[l1].y2, y3 = line[l2].y1, y4 = line[l2].y2;
ll t1 = (y3-y1)*(x1-x2)*(x3-x4) + x1*(y1-y2)*(x3-x4) - x3*(y3-y4)*(x1-x2);
ll t2 = (x3-x1)*(y1-y2)*(y3-y4) + y1*(x1-x2)*(y3-y4) - y3*(x3-x4)*(y1-y2);
ll t3 = (y1-y2)*(x3-x4) - (y3-y4)*(x1-x2);
if(t3==0 || t1%t3 || t2%t3) return;
ll x = t1/t3;
ll y = -t2/t3;
if(y1>y2) swap(y1,y2);
if(y3>y4) swap(y3,y4);
if(y>=y1 && y<=y2 && y>=y3 && y<=y4)
st.emplace(x,y);
}
int main(void)
{
#ifdef _LITTLEFALL_
freopen("in.txt","r",stdin);
#endif
int n = read();
ll ans = 0;
for(int i=0;i<n;i++)
{
Line &l = line[i];
l.x1 = read(); l.y1 = read();
l.x2 = read(); l.y2 = read();
if(l.x1>l.x2) swap(l.x1, l.x2), swap(l.y1, l.y2);
ans += __gcd(l.x2-l.x1, abs(l.y2-l.y1)) + 1;
}
for(int i=0;i<n;i++)
{
st.clear();
for(int j=0;j<i;j++)
intersection(i,j);
ans -= st.size();
}
printf("%I64d\n",ans );
return 0;
}