题解:关注洛谷 small_lemon_qwq 谢谢喵

洛谷 P1662。


打表,我和你拼了!

正解,我和你拼了!


众所周知,打表是一种非常优秀的算法,只是有以下缺点:

  • 无法提交(本题可以用分段打表,没有这个问题);
  • 被骂。

所以我们为了不被骂,只能另寻他法。

n = X n=X n=X

注意到,从 70 70 70 报数报到 79 79 79,每报一次数报数的方向就反一下,那么实际相当于报数的方向不变,并且报 80 80 80 的人就是报 70 70 70 的人,所以可以考虑直接将其优化掉,遇到非个位出现 7 7 7 直接将它变成 8 8 8,但是注意变成 8 8 8 不要超过了 n n n

这样时间复杂度就是了 O ⁡ ( 9 8 × 10 × 9 ) = O ⁡ ( 3874204890 ) ≈ O ⁡ ( 4 × 10 9 ) \operatorname{O}(9^8\times10\times9)=\operatorname{O}(3874204890)\approx\operatorname{O}(4\times10^9) O(98×10×9)=O(3874204890)O(4×109),显然无法通过,考虑优化检查是否存在为 7 7 7 的位这一步。

这个题解启发我们可以用高精度动态求检查是否存在为 7 7 7 的位,但我们不仅要判断是否存在为 7 7 7 的位,还要求出这个为 7 7 7 的位。我的做法是开一个栈存储所有为 7 7 7 的位,动态更新这个栈,查询时直接返回栈顶(如果有)。

考虑计算时间复杂度, O ⁡ ( 9 8 × 10 + 111111111 ) = O ⁡ ( 541578321 ) ≈ O ⁡ ( 5 × 10 8 ) \operatorname{O}(9^8\times10+111111111)=\operatorname{O}(541578321)\approx\operatorname{O}(5\times10^8) O(98×10+111111111)=O(541578321)O(5×108),其中 111111111 111111111 111111111 是高精度进位次数,卡一下午常就过了。

注意 C++11 和 C++14(GCC 9) 的区别。

#include<bits/stdc++.h>
using namespace std;
int d=1,x;
unsigned n,i=1,num[10]={1};
constexpr unsigned p[10]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
unsigned stk[10],tp;
void update(){
    register int k=0;
    ++num[0];
    tp+=(num[0]==7)-(num[0]==8);
    if(__builtin_expect(num[0]==7,0))stk[tp]=0;
    while(__builtin_expect(num[k]>9,0)){
        num[k]-=10;
        num[++k]++;
        tp+=(num[k]==7)-(num[k]==8);
        if(__builtin_expect(num[k]==7,0))stk[tp]=k;
    }
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
    // if(n==899999999){
    // 	cout<<959;
    // 	return 0;
      // }//看清楚,我注释了的
	#ifndef ONLINE_JUDGE
	auto start=clock();
	#endif
	while(__builtin_expect(i<=n,1)){
		x+=d;
		register int tmp=__builtin_expect(tp,0)?stk[tp]:(__builtin_expect(i%7==0,0)-1);
		if(tmp!=-1)d=~d+1;
		if(__builtin_expect(tmp>0,0)){
			if(__builtin_expect(i+p[tmp]<=n,1)){
				i+=p[tmp];
				++num[tmp];
				--tp;
			}else{
				if((n-i)&1)x+=d;
				break;
			}
			x+=d;
			d=~d+1;
			continue;
		}
		++i,update();
	}
	cout<<(x%1337+1336)%1337+1;
	#ifndef ONLINE_JUDGE
	cout<<"\n"<<clock()-start;
	#endif
	return 0;
}

这个代码 C++14(GCC 9) 会 TLE,不知道为什么,很玄学。

这样在 n = 10 9 n=10^9 n=109 时要跑 1.1 s 1.1s 1.1s,所以请后人继续努力,或增大时限。

### 关于洛谷 AT_ABC219_C Neo-lexicographic Ordering 的解题思路 对于给定的新字母顺序字符串 \(X\) 和一系列单词列表,目标是在新定义的字典序下对这些单词进行排序。此问题的核心在于理解如何依据自定义的字符优先级来比较两个字符串。 #### 字符串比较逻辑 为了按照新的字母表顺序排列字符串数组,需先构建一个映射关系,该映射能够将原始英文字母转换为对应的新位置编号。这可以通过遍历输入的字符串 \(X\) 来完成,并记录每个字符的位置索引作为其权重值[^4]。 ```python def create_mapping(order_string): mapping = {} for index, char in enumerate(order_string): mapping[char] = index return mapping ``` 有了这个映射之后,在对比任意两个字符串时就可以逐位检查它们对应的数值大小来进行判断: ```python def compare_strings(s1, s2, map_): min_length = min(len(s1), len(s2)) for i in range(min_length): if map_[s1[i]] != map_[s2[i]]: return -1 if map_[s1[i]] < map_[s2[i]] else 1 # If all characters are equal up to the length of shorter one, # then longer string should come after. if len(s1) == len(s2): return 0 elif len(s1) < len(s2): return -1 else: return 1 ``` 最后一步就是应用上述函数去调整整个字符串集合内的元素次序了。可以采用内置排序方法并指定 `key` 参数指向辅助比较功能;或者直接调用 Python 内置 sorted 函数配合 cmp_to_key 工具简化操作流程[^2]。 ```python from functools import cmp_to_key words.sort(key=cmp_to_key(lambda x,y :compare_strings(x, y, mapping))) print("\n".join(words)) ``` 以上即是对 ABC219C 题目——Neo-Lexicographical Order 的基本求解框架描述。值得注意的是实际编码过程中还需注意边界条件处理以及效率优化等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值