CSU 1810 Reverse

题意:

[i,j] 这个区间的数翻转一下和剩下的 nj+i1 个数形成一个新的大数,求所有翻转以后的数的和。

分析:

翻转以后的数由原来的数翻转部分的数组成。暴力枚举 i 开始的所有新的数的和。
l[i]表示前 i 个数形成的数的值。
r[i]表示后面 [j,n] 形成的数的值。
那么

ans[i]=j=in(r[1]r[i1])+r[j+1]+l[j]l[i1]10i110nj

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int maxn = 100010;
const int Mod = 1e9+7;

LL quickpow(LL x,int n,int Mod){
    LL ans = 1;
    while(n){
        if(n%2) ans = ans*x%Mod;
        x = x*x%Mod;
        n >>= 1;
    }
    return ans;
}

int n;
char str[maxn];
LL bit[maxn],inv[maxn],l[maxn],r[maxn],suml[maxn],sumr[maxn],sum[maxn];

LL calc(int i){
    LL ans = (r[1]-r[i]+Mod)*(n-i+1)%Mod;
    ans += (suml[n]-suml[i-1]+Mod)*bit[n-i+1]%Mod;
    ans %= Mod;
    LL tem = bit[n-i+1]*l[i-1]%Mod*(sum[n]-sum[i-1]+Mod)%Mod;
    ans = (ans+Mod-tem)%Mod;
    ans = (ans+sumr[n]-sumr[i]+Mod)%Mod;
    return ans;
}

void work(){
    LL ans = 0;
    for(int i = 1;i <= n;++ i){
        //cout << "calc:" << calc(i) << endl;
        ans += calc(i);
        ans %= Mod;
    }
    printf("%lld\n",ans);
}

int main(){
    //freopen("test.in","r",stdin);
    bit[0] = 1; for(int i = 1;i < maxn;++ i)    bit[i] = bit[i-1]*10%Mod;
    LL tem = quickpow(10,Mod-2,Mod);
    sum[0] = 0;
    inv[0] = 1; for(int i = 1;i < maxn;++ i)    inv[i] = inv[i-1]*tem%Mod;
    for(int i = 1;i < maxn;++ i)    sum[i] = (sum[i-1]+inv[i])%Mod;
    while(~scanf("%d",&n)){
        scanf("%s",str+1);
        l[0] = 0; r[0] = 0;
        l[n+1] = r[n+1] = 0;
        for(int i = 1;i <= n;++ i){
            l[i] = (l[i-1]+(str[i]-'0')*bit[i-1])%Mod;
        }
        for(int i = n;i >= 1;-- i){
            r[i] = (r[i+1]+(str[i]-'0')*bit[n-i])%Mod;
        }
        suml[0] = sumr[0] = 0;
        suml[n+1] = sumr[n+1] = 0;
        for(int i = 1;i <= n;++ i){
            suml[i] = (suml[i-1]+inv[i]*l[i])%Mod;
            sumr[i] = (sumr[i-1]+r[i])%Mod;
        }
        /*
        cout << "l:";
        for(int i = 1;i <= n;++ i)  cout << l[i] << " ";
        cout << endl;
        cout << "suml:";
        for(int i = 1;i <= n;++ i)  cout << suml[i] << " ";
        cout << endl;
        cout << "r:";
        for(int i = 1;i <= n;++ i)  cout << r[i] << " ";
        cout << endl;
        cout << "sumr:";
        for(int i = 1;i <= n;++ i)  cout << sumr[i] << " ";
        cout << endl;
        */
        work();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值