题意:对一个等差数列$a_i=A+Bi(0\leq i\leq n-1)$和非负整数$x$,把$a_i$的$10^x$位拿出来可以写成一个字符集为$0\cdots9$的字符串,现在给定这个字符串$d_{0\cdots n-1}$,求最小的$A$,或输出无解

如果$x\gt0$,那么有可能产生进位,所以$d_{i+1}-d_i$的取值最多能有$2$种,如果只有$1$种,显然$d_0$就是答案

如果有两种,这两种取值在$\bmod10$意义下必须相差$1$,较小那个($9\lt0$)就是$B$的$x-1$位

先扫一遍,用$B$的$x$位把$d_i$的$x$位向高位的进位复原,得到$d'_i$,现在条件变为$\left\lfloor\frac{a_i}{10^x}\right\rfloor=d'_i$,也可以写成$d'_i\cdot10^x\leq a_i\lt(d'_i+1)\cdot10^x$

我们已经知道了$d_i'$,现在要找到符合以上不等式的$a_i$并使得$a_0$最小,因为$x$越大限制越宽松,同时最小的$a_0$越大,所以考虑从小到大枚举$x$并判断是否能满足条件

实际上我们要找的是一条直线,它必须经过每条端点为$(i,d'_i\cdot10^x),(i,(d'_i+1)\cdot10^x)$的线段,两两枚举$d'_i$和$d'_j+1$,求出斜率的范围,然后不停增大$x$直到这个范围包含整数为止

虽然$n=10^4$,但因为atcoder评测机实在太快了,所以是能过的

以下是更快的方法(我没写==)

横纵坐标范围为$O(n)$的任意整点点集的凸包的大小为$O(n^{\frac23})$,证明如下(来自zjt)

先考虑求左下凸壳的大小,其他方向是一样的,这个凸壳的每条边对应的向量互相叉积$\gt0$,且所有向量的$x$之和和$y$之和都是$O(n)$级别的($x,y\geq0$)

对问题进行弱化:所有向量的$x+y$之和是$O(n)$的,并且我们不要求向量只需不相等

如果每个$(i,j)$都满足$i,j\leq m$,那么$\sum\limits_{i\leq m}\sum\limits_{j\leq m}i+j=O(n)$,即$m=O(n^{\frac13})$,所以不同的向量数只有$O(n^{\frac23})$个

所以凸包的大小也是$O(n^{\frac23})$,因为对问题做了三次弱化,所以实际上凸包上的点还会少很多

先求出所有$(i,d'_i\cdot10^x)$的上凸壳和$(i,(d'_i+1)\cdot10^x)$的下凸壳,由上述定理,在两个凸壳上枚举点对的时间复杂度为$O(n^{\frac43})$

最快当然还是在上凸壳枚举点,在下凸壳上的对应点只会单调地移动,时间复杂度$O(n)$

注意涉及到斜率作差时,如果坐标范围为$M$,$eps$一般要开到$\frac1{M^2}$,这个随便找一个极端情况就知道了

#include<stdio.h>
#include<string.h>
#include<set>
#include<math.h>
using namespace std;
typedef double du;
const du eps=1e-9;
char s[10010];
int a[10010];
set<int>d;
int go(int x,int y){return(y-x+10)%10;}
int main(){
	int n,i,j,dd,pw,B,res;
	du mn,mx;
	scanf("%s",s);
	n=strlen(s);
	for(i=0;i<n-1;i++)d.insert(go(s[i],s[i+1]));
	if(d.size()<2u){
		putchar(s[0]);
		return 0;
	}
	#define wa {puts("-1");return 0;}
	#define s1 *d.begin()
	#define s2 *d.rbegin()
	if(d.size()>2u||(go(s1,s2)!=1&&go(s2,s1)!=1))wa
	dd=s2==s1+1?s1:s2;
	a[0]=s[0]-'0';
	for(i=1;i<n;i++){
		a[i]=a[i-1]+dd;
		if(a[i]%10!=s[i]-'0')a[i]++;
		if(a[i]%10!=s[i]-'0')wa
	}
	mn=0;
	mx=1e9;
	for(i=0;i<n-1;i++){
		for(j=i+1;j<n;j++){
			mn=max(mn,(a[j]-(a[i]+1)+eps)/(du)(j-i));
			mx=min(mx,((a[j]+1)-a[i]-eps)/(du)(j-i));
		}
	}
	if(mn>mx)wa
	for(pw=1;ceil(mn*pw)>floor(mx*pw);pw*=10);
	B=floor(mx*pw);
	res=0;
	for(i=0;i<n;i++)res=max(res,a[i]*pw-B*i);
	printf("%d",res);
}

最新文章

  1. 【leetcode】Valid Palindrome
  2. ThinkPHP(3)SQL查询语句
  3. @SessionAttributes与HttpSession
  4. Linux diff patch
  5. linux中vi/vim显示行号设置
  6. 自制的七个C,总结的太好了
  7. ViewState的用法
  8. API访问客户端
  9. Win7下Redmine2.0.3+Mysql55+Ruby1.8.7成功安装记录分享
  10. JavaSE之认识java
  11. 基于MyBatis3.0.6的基本操作介绍
  12. 服务器文档下载zip格式
  13. java中Comparatable接口和Comparator接口的区别
  14. C++回顾day01---&lt;C++对C的增强&gt;
  15. rac 关库 启库
  16. 不可小视的String字符串
  17. 4:WPF中查看PDF文件
  18. Java_7.1 ArrayList应用点名器
  19. OpenGL ES 3.0之Fragment buffer objects(FBO)详解(一)
  20. DIY微型操作系统(2)—— 寄存器赋值

热门文章

  1. kartik\grid\GridView 合计,多选,导出excel,header修改 等方法集合!
  2. 【洛谷P2515【HAOI2010】】软件安装
  3. 【leetcode 简单】第十六题 二进制求和
  4. 35、def func(a,b=[]) 这种写法有什么坑?
  5. mysql数据库单表增删改查命令
  6. 【Tomcat】tomcat中server.xml配置详解
  7. Django1.10中文文档—模型
  8. BZOJ 3958 Mummy Madness
  9. 144.Binary Tree Preorder Traversal---二叉树先序、中序非递归遍历
  10. ActiveMQ-Prefetch机制和constantPendingMessageLimitStrategy