loj2511
引言
思维题。
这个做法跑得飞快,还不用 dp,也不是爆搜!
复杂度(可能)为 \(O(s^2t)\) 或 \(O(s^2)\),实际效率也是飞快。
不过这题我直接提交答案了。
思路
考虑 \(A=mn,B=m+n\)。
假设 \(A\) 先手。
从 \(A\) 中枚举分解方案,假设有 \((m_1,n_1)(m_2,n_2)\cdots(m_k,n_k)\) 这些合法。
如 \(k>1\),会说不知道,称这样的 \(A\) 构成集合 \(A_{>0}\);否则知道,称这样的 \(A\) 构成集合 \(A_0\)。
对 \(B\) 分解,其有 \((s,B-s)(s+1,B-s-1)\cdots(\lfloor B/2\rfloor,\lceil B/2\rceil)\) 这些合法。
从中选出相乘为 \(A_0\) 中元素的数对,若唯一,记这样的 \(B\) 构成 \(B_0'\),说明知道;若多于 \(1\) 个,则无法计算;若不存在,若解集大小为 \(1\),则构成集合 \(B_0\),说明知道;若解集大小大于 \(1\),构成集合 \(B_{>0}\)。
对 \(B_0\) 集合类似地反推 \(A_1'\),对 \(B_{>0}\) 反推出 \(A_1,A_{>1}\)。
刚才的描述不够清晰,让我们形式化地说:
\begin{array}{|l|}
\hline
X(A)\defeq\{(m,n)|s\le m\le n,mn=A\}\\
Y(B)\defeq\{(m,n)|s\le m\le n,m+n=B\}\\
A_{\ge0}\defeq\{A|X(A)\neq\varnothing\}\\
B_{\ge0}\defeq\{B|Y(B)\neq\varnothing\}\\\hdashline
A_0\defeq\{A|A\in A_{\ge0},|X(A)|=1\}\\
A_{\ge1}\defeq A_{\ge0}-A_0\\\hdashline
X_0\defeq\cup_{A\in A_0}X(A)\\
B_0'\defeq\{B|B\in B_{\ge0},|Y(B)\cap X_0|=1\}\\
B_0\defeq\{B|B\in B_{\ge0},|Y(B)-X_0|=1\}\\
B_{\ge1}\defeq\{B|B\in B_{\ge0},|Y(B)-X_0|>1\}\\\hdashline
Y_0\defeq\cup_{B\in B_0}Y(B)\\
A_1'\defeq\{A|A\in A_{\ge1},|X(A)\cap Y_0|=1\}\\
A_1\defeq\{A|A\in A_{\ge1},|X(A)-Y_0|=1\}\\
A_{\ge2}\defeq\{A|A\in A_{\ge1},|X(A)-Y_0|>1\}\\\hdashline
X_1\defeq\cup_{A\in A_1}X(A)\\
B_1'\defeq\{B|B\in B_{\ge1},|Y(B)\cap X_1|=1\}\\
B_1\defeq\{B|B\in B_{\ge1},|Y(B)-X_1|=1\}\\
B_{\ge2}\defeq\{B|B\in B_{\ge1},|Y(B)-X_1|>1\}\\\hdashline
\cdots\\
\hline
\end{array}
\]
查询 \(t=0\),就是查询 \(A_0/B_0'\);查询 \(t=1\),就是查询 \(B_0/A_1'\);查询 \(t=2\),就是查询 \(A_1/B_1'\);等等。
\(A_{\ge1}\) 就是 \(A\) 报了一次不知道后的可能集合;\(B_{\ge1}\) 就是 \(B\) 报了一次不知道后的可能集合;\(A_{\ge2}\) 就是 \(A\) 报了两次不知道后的可能集合;等等。
B 先手同理。
试看看!
你已经学会基本的思考方法了,让我们来做一些小练习吧!
实战一些数据。
测试点 \(2\)
1 Alice 2
对,先 \(2\) 再 \(1\)。
主要是因为啊,这个东西嘛,和我们刚刚说的一样,是 A 先手,不用重新转换视角。
对这种东西,我们可以考虑对下面的东西列表格:
\]
\]
这样的手算会简单一点。(?)
\hline
n&1&2&3&4&5&6&7
\\\hline\hline
f(n)&0&0&0&1&0&\ge1&0
\\\hline
g(n)&-1&0&0&0&\ge1&\ge1&\ge1
\\\hline
\end{matrix}
\]
因此 \(m=1,n=4\) 最优。
测试点 \(1\)
1 Bob 2
反过来枚举顺序,即得如下。
\hline
n&1&2&3&4&5&6&7
\\\hline\hline
f(n)&0&0&0&\ge1&0&\ge1&0
\\\hline
g(n)&-1&0&0&1&\ge1&\ge1&\ge1
\\\hline
\end{matrix}
\]
\(m=n=2\) 最优。
测试点 \(3\)
2 Bob 2
类似,但是要手枚更多项。
\hline
n&1&2&3&4&5&6&7&8&9&10&11&12
\\\hline\hline
f(n)&-1&-1&-1&0&-1&0&-1&0&0&0&-1&\ge1
\\\hline
g(n)&-1&-1&-1&0&0&1&1&\ge1&\ge1&&&
\\\hline
\end{matrix}
\]
\(m=3,n=4\) 最优。
注意不是 \(2,4\)——\(8\) 已经置 \(0\) 了!
测试点 \(4\)
11 Bob 2
已经不能指望手算了——刚刚的那组数据都很困难。
考虑代码实现以上过程。
\(t=2\) 时,\(B=m+n\) 在 \(4s\) 内较有可能,考虑仅计算 \(mn\le4s^2+100,m+n\le5s+100\) 的部分解集。
首先提取范围内的 \(A_{\ge0}\) 与 \(B_{\ge0}\),并算出对应的 \(X(A),Y(B)\)。
然后枚举 \(B_0\),得到 \(B_{\ge1}\)。
枚举 \(A_0\),得到 \(A_{\ge1}\)。
枚举 \(B_1\),进而得解。
成功地,给出了解 \(n=15,m=16\)。
测试点 \(5\)
18 Bob 2
这个给出的解为 \(n=21,m=24\),交了一下是错的,是不是我们给的界不够大?
不是,其实是因为,我们没有再校验 \(A_1'\)!
在从 \(B_1\) 推断 \(A_1'\) 后,我们还要校验其合法性:\(A_1'\) 不一定可以被唯一决策!
验证完后即得正解 \(n=20,m=27\)。
测试点 \(6\sim10\)
28 Bob 2
28 Alice 2
57 Alice 2
111 Alice 2
200 Alice 2
把从 \(A\) 出发的情况实践一下 容易依次得解。
这样我们就解决了 \(t=2\) 的部分(测试点 \(1\sim10\)),答案依次为
2 2
1 4
3 4
15 16
20 27
35 40
28 45
65 72
114 140
200 242
可以拿到 \(\rm40pts\)。
以下是暴力代码。
int main()
{
#ifdef MYEE
freopen("QAQ.in","r",stdin);
// freopen("QAQ.out","w",stdout);
#endif
static chr Op[50];
uint s,t;scanf("%u%s%u",&s,Op,&t);
if(t!=2)exit(0);
static std::vector<std::pair<uint,uint> >X[1000005],Y[1000005];
uint Lim1=4*s*s,Lim2=5*s;
for(uint m=s;m<=Lim2;m++)for(uint n=m;n*m<=Lim1&&n+m<=Lim2;n++){
X[n*m].push_back({m,n});
Y[n+m].push_back({m,n});
}
static bol Xi[1000005],Yi[1000005];
std::vector<uint>Ag,Bg;
for(uint i=1;i<=Lim1;i++)if(X[i].size())Ag.push_back(i),Xi[i]=1;
for(uint i=1;i<=Lim2;i++)if(Y[i].size())Bg.push_back(i),Yi[i]=1;
if(Op[0]=='B'){
std::vector<uint>User;
User.clear();
for(auto b:Bg){
uint c=0;
for(auto g:Y[b])c+=Xi[g.first*g.second];
if(c>=2)User.push_back(b);
else Yi[b]=0;
}
Bg=User,User.clear();
for(auto a:Ag){
uint c=0;
for(auto g:X[a])c+=Yi[g.first+g.second];
if(c>=2)User.push_back(a);
else Xi[a]=0;
}
Ag=User,User.clear();
for(auto b:Bg){
uint c=0;
for(auto g:Y[b])c+=Xi[g.first*g.second];
if(c==1)User.push_back(b);
else Yi[b]=0;
}
for(auto b:User)for(auto g:Y[b])if(Xi[g.first*g.second]){
uint c=0;
for(auto p:X[g.first*g.second])c+=Yi[p.first+p.second];
if(c==1){
printf("%u %u\n",g.first,g.second);
return 0;
}
}
}
else{
std::vector<uint>User;
User.clear();
for(auto a:Ag){
uint c=0;
for(auto g:X[a])c+=Yi[g.first+g.second];
if(c>=2)User.push_back(a);
else Xi[a]=0;
}
Ag=User;
User.clear();
for(auto b:Bg){
uint c=0;
for(auto g:Y[b])c+=Xi[g.first*g.second];
if(c>=2)User.push_back(b);
else Yi[b]=0;
}
Bg=User,User.clear();
for(auto a:Ag){
uint c=0;
for(auto g:X[a])c+=Yi[g.first+g.second];
if(c==1)User.push_back(a);
else Xi[a]=0;
}
uint x=-1,y=-1;
for(auto a:User)for(auto g:X[a])if(Yi[g.first+g.second]){
uint c=0;
for(auto p:Y[g.first+g.second])c+=Xi[p.first*p.second];
if(c==1){
if(g.first+g.second<x+y||(g.first+g.second==x+y&&g.first<x))
x=g.first,y=g.second;
}
}
printf("%u %u\n",x,y);
}
return 0;
}
测试点 \(11\sim25\)
看下面 \(5\) 组数据(\(11\sim15\))。
1 Bob 3
69 Alice 3
147 Alice 4
88 Alice 5
109 Bob 6
考虑到刚刚的做法,其不能进一步应用于 \(t>2\),主要是因为我们无法确定答案的值域,刚刚的做法是挂掉的(必须得有数目足够多的元素在外围“盖住”当前的答案,使得不会有更小解被误选择)。
我们猜测实际值域不会很大,尝试把刚才的过程再做几轮,试着跑一跑?
这部分代码如下:
int main()
{
#ifdef MYEE
freopen("QAQ.in","r",stdin);
// freopen("QAQ.out","w",stdout);
#endif
static chr Op[50];
uint s,t;scanf("%u%s%u",&s,Op,&t);
if(t>6)exit(0);
static std::vector<std::pair<uint,uint> >X[1000005],Y[1000005];
uint Lim1=4*s*s+100,Lim2=5*s+100;
for(uint m=s;m<=Lim2;m++)for(uint n=m;n*m<=Lim1&&n+m<=Lim2;n++){
X[n*m].push_back({m,n});
Y[n+m].push_back({m,n});
}
static bol Xi[1000005],Yi[1000005];
std::vector<uint>Ag,Bg;
for(uint i=1;i<=Lim1;i++)if(X[i].size())Ag.push_back(i),Xi[i]=1;
for(uint i=1;i<=Lim2;i++)if(Y[i].size())Bg.push_back(i),Yi[i]=1;
std::vector<uint>User;
for(uint i=0;i<t;i++)if(!(i&1)==(*Op=='B')){
for(auto b:Bg){
uint c=0;
for(auto g:Y[b])c+=Xi[g.first*g.second];
if(c>=2)User.push_back(b);
else Yi[b]=0;
}
Bg=User,User.clear();
}
else{
for(auto a:Ag){
uint c=0;
for(auto g:X[a])c+=Yi[g.first+g.second];
if(c>=2)User.push_back(a);
else Xi[a]=0;
}
Ag=User,User.clear();
}
if((t&1)==(*Op=='B')){
for(auto a:Ag){
uint c=0;
for(auto g:X[a])c+=Yi[g.first+g.second];
if(c==1)User.push_back(a);
else Xi[a]=0;
}
uint x=-1,y=-1;
for(auto a:User)for(auto g:X[a])if(Yi[g.first+g.second]){
uint c=0;
for(auto p:Y[g.first+g.second])c+=Xi[p.first*p.second];
if(c==1){
if(g.first+g.second<x+y||(g.first+g.second==x+y&&g.first<x))
x=g.first,y=g.second;
}
}
printf("%u %u\n",x,y);
}
else{
for(auto b:Bg){
uint c=0;
for(auto g:Y[b])c+=Xi[g.first*g.second];
if(c==1)User.push_back(b);
else Yi[b]=0;
}
for(auto b:User)for(auto g:Y[b])if(Xi[g.first*g.second]){
uint c=0;
for(auto p:X[g.first*g.second])c+=Yi[p.first+p.second];
if(c==1){
printf("%u %u\n",g.first,g.second);
return 0;
}
}
}
return 0;
}
依次分别得到
1 4
80 84
162 170
100 110
126 128
似乎……也不是很大?
交一下……是对的!
胆子放大点,继续来做 \(16\sim20\)!
把代码改一下,运行
4 Bob 7
117 Alice 8
161 Alice 9
134 Alice 10
77 Bob 11
得到输出
4 12
128 135
182 184
135 176
78 108
还是很小啊!
直接把剩下的(\(21\sim25\))都跑一遍。
177 Bob 12
178 Bob 13
179 Bob 14
180 Bob 15
178 Alice 15
得到输出
185 216
180 222
192 210
180 224
196 208
直接就过了!!!
总复杂度不会证明,但应该是 \(O(s^2t)\) 或 \(O(s^2)\) 的。
Code
最终代码不给了,把上面那个 \(t\le6\) 的代码改一改就是了。
提交答案题一份代码速通的艺术是怎样的啊。
loj2511的更多相关文章
随机推荐
- vue后退页面刷新数据和缓存数据
我们在项目中经常使用this.$router.go(-1) 但是,有时我们需要把前一个页面的数据进行缓存,有时需要刷新数据,下面来记录一下怎么操作吧 首先:在vue项目中缓存页面我们能想到 keep ...
- pythonfloat优雅的四舍五入
开发中经常会有float四舍五入转int的需求,先看看浮点数直接转int的情形:无论如何float直接转int都不会四舍五入,而是直接抹去小数点. 这个需求很简单,实现也很简单,看过网友的实现,都不够 ...
- 4、PageHelper分页查询
1.MyBatis的分页方式: 逻辑分页与物理分页 1.逻辑分页:使用MyBatis自带的RowBounds进行分页,是一次性查询很多数据,然后再在结果中检索分页的数据.这样做弊端是需要消耗大量的内存 ...
- [机器学习] Yellowbrick使用笔记5-回归可视化
回归模型试图预测连续空间中的目标.回归计分可视化工具显示模型空间中的实例,以便更好地理解模型是如何进行预测的.代码下载 Yellowbrick已经实施了三种回归评估: 残差图Residuals Plo ...
- tempdb数据文件暴增分析
背景 某客户tempdb数据文件突然暴增,导致磁盘可用空间紧张,让我们找到暴增的原因. 现象 登录到SQL专家云,通过趋势分析进行回溯,在4月12日,tempdb数据文件在3个小时内从10GB涨到了8 ...
- 数据分析中的SQL如何解决业务问题
本文来自知乎问答. 提问:数据分析人员需要掌握sql到什么程度? 请问做一名数据分析人员,在sql方面需要掌握到什么程度呢?会增删改查就可以了吗?还是说关于开发的内容也要会?不同阶段会有不同的要求吗? ...
- Excelize 2.7.0 发布, 2023 年首个更新
Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基于 ECMA-376,ISO/IEC 29500 国际标准.可以使用它来读取.写入由 Microsoft Exc ...
- [Unity]限制一个值的大小(Clamp以及Mathf)
如何限制一个物体的运动范围? 代码实例 public float xMin, xMax, zMin, zMax; rigidbody.position = new Vector3( Mathf.Cla ...
- 全志R528 系统繁忙时触摸屏I2C报错问题。
最近调试项目时遇到一个奇怪的问题. 当linux 系统繁忙时(开机,关机或APP繁忙等情况),此时按下触摸屏后, I2C总线就会报错,TP读数据失败,之后内存报错,重启. root@TinaLinux ...
- py教学之列表
列表是什么 list 是一些元素按照一定顺序排列的元素集合 序列是 Python 中最基本的数据结构. 序列中的每个值都有对应的位置值,称之为索引,第一个索引是 0,第二个索引是 1,依此类推. Py ...