CodeForces - 1422C - Bargain 枚举贡献

CodeForces - 1422C - Bargain 枚举贡献

题意:给出长度为n的字符串,删除其中任意长度的连续子串,将所有可能的情况的数字加起来取模

做法:假设序列是12354,假设2不被删去
那么可能的情况有以下两种:

  • 删除位置[3,5]中的连续子串
    这种情况下,2的贡献是不同的,分别是:
    删除长度为3的子串 2 × 1 0 0 × 1 2×10^0×1 2×100×1
    删除长度为2的子串: 2 × 1 0 1 × 2 2×10^1×2 2×101×2
    删除长度为1的子串: 2 × 1 0 2 × 3 2×10^2×3 2×102×3
    a n s 1 = ∑ i = 1 n ( ( s [ i ] − ′ 0 ′ ) × ∑ j = 1 n − i j 1 0 j − 1 ) ans1=\sum_{i=1}^{n}((s[i]-'0')×\sum_{j=1}^{n-i}j10^{j-1}) ans1=i=1n((s[i]0)×j=1nij10j1)
  • 删除位置[1,1]中的连续子串
    这种情况下,2的贡献是相同的,只需要算有多少种情况即可
    a n s 2 = ∑ i = 1 n ( ( s [ i ] − ′ 0 ′ ) × 1 0 n − i × i ( i − 1 ) / 2 ) ans2=\sum_{i=1}^{n}((s[i]-'0')×10^{n-i}×i(i-1)/2) ans2=i=1n((s[i]0)×10ni×i(i1)/2)

输出ans1+ans2即可

代码

const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
const ll mod=1e9+7;
char s[maxn];
ll f[maxn],ans=0,n;
ll qpow(ll a,ll b,ll mod){ll res=1;while(b){if (b&1)res=(res*a)%mod;a=a*a%mod;b>>=1;}return res;}
int main()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    rep(i,1,n)f[i]=(f[i-1]+(i*qpow(10,i-1,mod)%mod))%mod;
    for (ll i=n;i>=1;i--)
    {
        ans=(ans+f[n-i]*(s[i]-'0')%mod)%mod;
        ans=(ans+(s[i]-'0')*qpow(10,n-i,mod)%mod*((i*(i-1)/2)%mod)%mod)%mod;
    }
    WW(ans);
    return 0;
}



拓展:一开始读错题了,以为是删去任意长度的子序列(不一定连续),这种情况下,可以直接线性递推,假设 [ 1 , i ] [1,i] [1,i]的串可以构成的答案是ans,把 s [ i + 1 ] s[i+1] s[i+1]放进来

  • 如果取它,那么之前的答案相当于左移一位=10ans,并且计算出有多少个新加进来的 s [ i + 1 ] s[i+1] s[i+1]
  • 如果不取它,仍然是ans

由于不能一个都不删,所以得把它自身减去就是答案了

代码

const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
const ll mod=1e9+7;
char s[maxn];
ll qpow(ll a,ll b,ll mod){ll res=1;while(b){if (b&1)res=(res*a)%mod;a=a*a%mod;b>>=1;}return res;}
int main()
{
    scanf("%s",s+1);
    int n=strlen(s+1);
    ll x=0,ans=0;
    for(int i=n;i>=1;i--)x=(x+qpow(10,n-i,mod)*(s[i]-'0')%mod)%mod;
    rep(i,1,n)ans=(ans*11%mod+qpow(2,i-1,mod)*(s[i]-'0')%mod)%mod;
    WW((ans-x+mod)%mod);
    return 0;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值