UVA11768 - Lattice Point or Not

本文详细解析在线裁判2868题目的解题思路,通过将坐标转换并利用直线方程,解决横纵坐标均为特定倍数点的数量问题。文章探讨了边界条件、扩展欧几里德算法的应用及特殊情况处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2868

题解

这题本身不难,但是边界情况容易造成 W A \color{red}WA WA
我先把坐标读入进来并且乘以 10 10 10,容易写出直线的一般方程 ( y 1 − y 2 ) x + ( x 2 − x 1 ) y = x 2 y 1 − x 1 y 2 (y_1-y_2)x+(x_2-x_1)y=x_2y_1-x_1y_2 (y1y2)x+(x2x1)y=x2y1x1y2
用字母代替系数,得到直线方程 a x + b y = c ax+by=c ax+by=c
现在就是要找横纵坐标都是 10 10 10的倍数的点,其个数就是答案
解不定方程 10 a x + 10 b y = c 10ax+10by=c 10ax+10by=c x ∈ [ x 1 , x 2 ] x\in[x_1,x_2] x[x1,x2],解的个数就是答案
如果 ( 10 ( a , b ) ) ̸ ∣ c (10(a,b))\not|c (10(a,b))̸c,方程无解,点数是 0 0 0
否则解 10 a x ′ + 10 b y ′ = ( 10 a , 10 b ) 10ax'+10by'=(10a,10b) 10ax+10by=(10a,10b)
假设解出一组 x ′ = x 0 , y ′ = y 0 x'=x_0,y'=y_0 x=x0,y=y0
解集构造为 x = x 0 c ( 10 a , 10 b ) + k b ( a , b ) x=x_0\frac{c}{(10a,10b)}+k\frac{b}{(a,b)} x=x0(10a,10b)c+k(a,b)b
10 x ∈ [ x 1 , x 2 ] 10x\in[x_1,x_2] 10x[x1,x2]
0.1 x 1 ≤ x 0 c ( 10 a , 10 b ) + k b ( a , b ) ≤ 0.1 x 2 0.1x_1\leq x_0\frac{c}{(10a,10b)}+k\frac{b}{(a,b)} \leq 0.1x_2 0.1x1x0(10a,10b)c+k(a,b)b0.1x2
解得 ( a , b ) b ( 0.1 x 1 − x 0 c ( 10 a , 10 b ) ) ≤ k ≤ ( a , b ) b ( 0.1 x 2 − x 0 c ( 10 a , 10 b ) ) \frac{(a,b)}{b}(0.1x_1-x_0\frac{c}{(10a,10b)})\leq k \leq\frac{(a,b)}{b}(0.1x_2-x_0\frac{c}{(10a,10b)}) b(a,b)(0.1x1x0(10a,10b)c)kb(a,b)(0.1x2x0(10a,10b)c)
利用取整函数求出 k k k的个数就好了
P a y   A t t e n t i o n ! \color{red}Pay\ Attention! Pay Attention!
当我在整个不等式中除以 b b b时,我相当于默认了 b ̸ = 0 b\not=0 b̸=0,但是如果 b = 0 b=0 b=0,这个算法算出的答案就错了
所以这里一定要单独讨论(WA了5发)

代码

//扩展欧几里德
#include <bits/stdc++.h>
#define ll long long
#define eps 1e-8
using namespace std;
ll read(ll x=0)
{
	ll c, f=1;
	for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-48;
	return f*x;
}
ll gcd(ll a, ll b){return !b?a:gcd(b,a%b);}
void exgcd(ll a, ll b, ll &x, ll &y)
{
	if(b==0){x=1, y=0;return;}
	ll xx, yy;
	exgcd(b,a%b,xx,yy);
	x=yy, y=xx-a/b*yy;
}
ll work()
{
	ll a, b, c, g, x0, y0, x1, y1, x2, y2;
	double l, r, tmp;
	scanf("%lf",&tmp), x1=tmp*10;
	scanf("%lf",&tmp), y1=tmp*10;
	scanf("%lf",&tmp), x2=tmp*10;
	scanf("%lf",&tmp), y2=tmp*10;
	a=y1-y2, b=x2-x1, c=-x1*y2+x2*y1;
	if(b==0)
	{
		if(x1%10!=0)return 0;
		if(y1*y2<0)return abs(y1)/10+abs(y2)/10+1;
		return max(abs(y1),abs(y2))/10-min(abs(y1)-1,abs(y2)-1)/10;
	}
	g=gcd(a,b);
	if(c%(10*g)!=0)return 0;
	exgcd(10*a,10*b,x0,y0);
	l=0.1*(x1-x0*c/g)*g/b;
	r=0.1*(x2-x0*c/g)*g/b;
	if(l>r+eps)swap(l,r);
	return (ll)(floor(r+eps)-ceil(l-eps)+1);
}
int main()
{
	ll T=read();
	while(T--)printf("%lld\n",work());
	return 0;
}
### Flat-Lattice 的概念 Flat-lattice 是一种用于处理自然语言处理任务的数据结构,特别是在涉及词典信息的任务中表现出色。这种结构能够将复杂的 lattice 展平成更易于处理的形式,同时保留原有的语义关系[^2]。 在具体实现方面,flat-lattice 可以定义为一组跨度(span),其中每个跨度代表一个标记(即字符或单词),并附带头部和尾部索引,用来指示该标记在原序列中的起始和结束位置。对于单个字符而言,其头部和尾部索引相同;而对于多字符组成的词语,则会记录下整个词语范围内的首尾位置。 ### Flat-Lattice 的实现方式 为了更好地理解 flat-lattice 如何运作,下面给出一段 Python 代码作为示例: ```python class Span: def __init__(self, start, end, label): self.start = start self.end = end self.label = label def build_flat_lattice(tokens, dictionary): spans = [] # 构建基于字面意思的初始span列表 for i, token in enumerate(tokens): span = Span(i, i+1, 'char') spans.append(span) # 添加来自词典的新spans for entry in dictionary.entries(): positions = find_sublist_positions(tokens, entry.tokens()) for pos in positions: new_span = Span(pos, pos+len(entry), entry.name) spans.append(new_span) return sorted(spans, key=lambda s: (s.start, -s.end)) ``` 此函数 `build_flat_lattice` 接收两个参数:一个是待分析的文本分词结果 `tokens` ,另一个是从外部加载得到的领域特定术语库 `dictionary` 。通过遍历这些输入数据,程序创建了一系列 Span 对象,并按照它们在原文档中的顺序进行了排序。 ### 应用场景 FLAT 模型利用了上述提到的 flat-lattice 结构,在 Transformer 编码器之上引入了一种新的位置编码机制,使得模型能够在不改变内部架构的情况下融入额外的知识源——比如预先编译好的词汇表。这种方法不仅提高了实体识别任务的表现精度,同时也保证了高效的 GPU 并行运算能力[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值