CodeForces 1422 C Bargain 题解

题意

给你一个数 a(长度为 |a| ) ,你可以从这个数中选择一段子串并删掉,两端再拼成一个新数,问所有可能的新数的和mod109+7

Data Range:

|a|<=105

变量声明

a=a1a2a3an

n|a|

思路

|a|<=105

看一下范围,暴力是不可能的了

那就要分别考虑每个数位对答案的贡献。

假设当前数位为第 k 位,

那么删去的串一定在第 k 位前或者后面。

在第 k 位前

产生的新数中,ak 后面一定有 nk 位,对答案的贡献为 10nkak

这种数有 (k2)

总贡献为 (k2)10nkak

在第 k 位后

产生的新数中,ak 后面的位数与在后面删去的个数有关.

若在后面删去 x(xnk) 位, 这种数对答案的贡献为 10nkxak

共有 nkx+1 种。

对答案的贡献为 10nkxak(nkx+1)

这种情况总的对答案贡献为

x=1nk10nkxak(nkx+1)

直接这么算,肯定要超时了,我们注意到:

10nkx

nkx+1

也就是说,对于每项,都可以表示为 10t(t+1)ak

而只有 ak 是不确定的,

因此,我们维护一个数组,只记录各项 ak 的和,到时候再乘上 10nkx(nkx+1) 就可以了。

又因为 x[1,nk] ,每次处理 ak 都是一次区间加,而最后计算结果时是一位一位的求值,维护一个差分数组就行了。

代码

头文件、快读等自由脑补

#define ll long long

using namespace std;

const int MAXN = 1e5+10;
const int mod = 1e9+7;

int n = 0;
ll a[MAXN],c[MAXN],p10[MAXN],ans = 0;

int main (){
    while(scanf("%1lld",&a[n+1]) == 1) n++;
    p10[0] = 1;
    for(int i = 1;i <= n;i++) p10[i] = p10[i-1] * 10 % mod;
    //p10[i] 10^i
    for(ll i = 1;i <= n;i++){
		ans += (i*(i-1)/2)%mod * p10[n-i] %mod* a[i]%mod;
		if(ans >= mod) ans %= mod;
        //在第i位前
		c[n-i+1] = (c[n-i+1]-a[i])%mod;
		c[1] = (c[1]+a[i])%mod;
        //根据推导,对数组进行区间加(实际上是对差分数组修改)
    }
    ll te = 0;
    for(int i = 1;i <= n;i++){
		te = (te+c[i])%mod; //还原数组
		ans = (ans + te * p10[i-1] % mod * i%mod)%mod; //计算第二部分答案
    }
    printf("%lld",ans%mod);
    return 0;
}

posted @   Werner_Yin  阅读(438)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示