AtCoder Beginner Contest 338 G. evall(枚举+递推 统计贡献)

2024-02-04 11:20

本文主要是介绍AtCoder Beginner Contest 338 G. evall(枚举+递推 统计贡献),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目

长为1e6的串,只由数字1-9、加号+、乘号*组成,

对1<=i<=j<=n,只要s[i]和s[j]均为数字,就将eval(i,j)(求值表达式)的值加入答案内

求答案对998244353取模的值

换言之,求以下程序的结果

s = input()
n = len(s)
ans, mod = 0, 998244353
def ok(x):return '0'<=x<='9'
for i in range(n):for j in range(i,n):if ok(s[i]) and ok(s[j]):ans = (ans + eval(s[i:j+1])) % mod
print(ans)

思路来源

乱搞ac

题解

把连乘的段单独处理,统计每一段的贡献

如果左侧顶到一个+号,那么加号往左的都可以取,右侧同理

如果左侧不是加号,那么左侧只能卡到i 

1234*2345*3456

枚举i=2时,这一位的贡献有:

2 23 234

234*2 234*23 234*234 234*2345

234*2345*3 234*2345*34 234*2345*345 234*2345*3456

发现需要处理一个形如(3+34+345+3456)的东西,

还需要处理一个形如2345*(3+34+345+3456)的东西,并加上2+23+234

于是开了一堆数组维护这些内容,

pre[i]表示i前有几个数字,suf[i]表示i后有几个数字

尺取相邻加号之间的段,处理连乘的贡献,

不妨称3+34+345+3456这样的段,叫3456这个数的前缀贡献

sum[i]形如(3+34+345+3456)+(2+23+234+2345),

只需要某个数的前缀贡献的时候,作差得到

sum2[i]形如2+23+234+2345*(3+34+345+3456),

转移要么乘上一个数,要么加上这个数的前缀贡献,可以递推实现

由4+45+456需要得到3+34+345+3456时,加上3333即可,

所以ten[i]维护10的幂次,形如1000,sten[i]维护其前缀和,形如1111

las[i]记录i这个位置后面的第一个符号的位置,可能为乘号或者加号

now[i]记录i这个位置所在的段往后延伸到尾部时,这个数字是多少

mul[i]表示i这个位置往后的第一个完整的数到尺取段尾这一段区间的积是多少

比如1+23*45*56+7,mul[4]表示45*56的值,而mul[3]表示23*45*56的值

总之,就是通过手玩发现,需要通过枚举+数贡献的方式计数,然后就是xjb乱搞

代码

#include<bits/stdc++.h>
#include<cstdio>
#include<vector>
#include<map>
#include<queue>
#include<array>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
using namespace std;
const int N=1e6+10,mod=998244353;
char s[N];
int n,pre[N],suf[N],sum[N],sum2[N],mul[N];
int ten[N],sten[N],cur,w,las[N],now[N],ans;
void add(int &x,int y){x=(x+y)%mod;
}
bool ok(char x){return '0'<=x && x<='9';
}
int cal(int l,int r){return (sum[l]-sum[r+1]+mod)%mod;
}
int main(){scanf("%s",s+1);n=strlen(s+1);s[0]=s[n+1]='+';ten[0]=sten[0]=1;rep(i,1,n){ten[i]=10ll*ten[i-1]%mod;sten[i]=(sten[i-1]+ten[i])%mod;}rep(i,1,n){pre[i]=pre[i-1]+ok(s[i]);}per(i,n,1){suf[i]=suf[i+1]+ok(s[i]);}for(int j=n+1;j>=0;){if(s[j]=='+'){mul[j]=1;las[j]=j;j--;continue;}int k=j;while(k && s[k]!='+')k--;cur=w=0;for(int i=j;i>k;--i){las[i]=las[i+1];sum[i]=sum[i+1];sum2[i]=sum2[i+1];mul[i]=mul[i+1];if(s[i]=='*'){cur=w=0;las[i]=i;continue;}cur++;int v=s[i]-'0';w=(w+1ll*v*ten[cur-1]%mod)%mod;now[i]=w;sum[i]=(sum[i+1]+1ll*v*sten[cur-1]%mod)%mod;//printf("i:%d sum2i:%d\n",i,sum2[i]);if(!ok(s[i-1])){sum2[i]=cal(i,las[i]-1)%mod;sum2[i]=(sum2[i]+1ll*w*sum2[las[i]]%mod)%mod;mul[i]=1ll*mul[i]*w%mod;}//printf("i:%d sum:%d sum2:%d las:%d cal:%d w:%d pre:%d\n",i,sum[i],sum2[i],las[i],cal(i,las[i]-1),w,sum2[las[i]]);}for(int i=k+1;i<=j;++i){if(s[i]=='*')continue;int w1=1ll*now[i]*sum2[las[i]]%mod;//*后面的sum2 和*前面结尾1的贡献 左端点在i 右端点在las[i]+号左的贡献int bs=(i==k+1?pre[k]+1:1);//左侧+左的也可以取(i=k+1时可以再往左任取)int w2=1ll*now[i]*mul[las[i]]%mod*suf[j+1]%mod;//右侧+右的也可以取 左端点在i 右端点在las[i]+号右的贡献int w3=cal(i,las[i]-1);w=(w1+w2)%mod;w=(w+w3)%mod;w=1ll*w*bs%mod;ans=(ans+w)%mod;//printf("i:%d s:%d las:%d now:%d bs:%d sum2lasi:%d w1:%d w2:%d w3:%d w:%d ans:%d\n",i,s[i]-'0',las[i],now[i],bs,sum2[las[i]],w1,w2,w3,w,ans);}j=k;}printf("%d\n",ans);return 0;
}
//2*(2+2*3+2*34)
/*
1*mul[2]
1*2*mul[3]
1*2*3*mul[4]
mul[3]+3*mul[4]
当前数做积2345*(3+34+345+3456)
+2+23+234+2345
每一段先乘完整数 然后加mul
两层递推
*/
/*
1+10*11+2
1 (2)
10 (2) 
10*1 (2)
10*11 (4)
*//*8 8*3 8*3*3 8*3*33*/

这篇关于AtCoder Beginner Contest 338 G. evall(枚举+递推 统计贡献)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/677325

相关文章

SQL Server中,查询数据库中有多少个表,以及数据库其余类型数据统计查询

sqlserver查询数据库中有多少个表 sql server 数表:select count(1) from sysobjects where xtype='U'数视图:select count(1) from sysobjects where xtype='V'数存储过程select count(1) from sysobjects where xtype='P' SE

WDF驱动开发-WDF总线枚举(一)

支持在总线驱动程序中进行 PnP 和电源管理 某些设备永久插入系统,而其他设备可以在系统运行时插入和拔出电源。 总线驱动 必须识别并报告连接到其总线的设备,并且他们必须发现并报告系统中设备的到达和离开情况。 总线驱动程序标识和报告的设备称为总线的 子设备。 标识和报告子设备的过程称为 总线枚举。 在总线枚举期间,总线驱动程序会为其子 设备创建设备对象 。  总线驱动程序本质上是同时处理总线枚

统计是一门艺术(点估计)

1 点估计 1.1 点估计理解(point estimate) 总体,样本属于参数空间 一般未知,要由样本对作一个估计,或对作一个估计,这种估计称为点估计 通常用记为的一个点估计。 1.2 点估计的方法 (1)矩估计: 就是用样本矩来代替总体矩,当然有好有坏 设为总体的一个简单随机样本,, 分别称, 为k阶样本原点矩和k阶样本中心矩. 记 为什么能用矩估计?

Codeforces April Fools Day Contest 2014(附官方题解)

Codeforces2014年愚人节的坑题。。。但还是感觉挺好玩的。。。 A. The Great Game time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Two teams mee

Codeforces April Fools Day Contest 2013

2013年愚人节的坑题。。。 A. Mysterious strings time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Input The input contains a sin

atcoder ABC 359-B题详解

atcoder ABC 359-B题详解 Problem Statement There are 2N people standing in a row, and the person at the i-th position from the left is wearing clothes of color Ai. Here, the clothes have N colors from 1

金蝶盘点机PDA进行工序汇报扫描,工时工资统计使用说明书

使用盘点机PDA扫描商品条码(序列号)进行工序汇报,自动生成电脑里的【工序汇报单】,自动计算工时,工资。这样就不用去电脑上人工手工一行行录单,大大提高工作效率和数据准确性。 操作时,只需要商品条码(序列号)即可实现快速,准确的工序汇报。从而防止电脑进行工序汇报耗时,费事,不准确的问题。 注意商品条码规则:产品代码+钢管长度+炉号+管号+合同号+序列号 下面我们看下【工序汇报单】的操作步骤

地推利器Xinstall:全方位二维码统计,打造高效地推策略,轻松掌握市场脉搏!

在移动互联网时代,地推作为一种传统的推广方式,依然占据着重要的地位。然而,随着市场竞争的加剧,地推也面临着诸多挑战,如如何有效监测下载来源、解决填码和人工登记的繁琐、避免重复打包和iOS限制、以及如何准确考核推广业绩等。针对这些痛点,Xinstall作为一款强大的移动应用统计与推广平台,推出了全面的地推二维码统计功能,助力地推人员轻松应对各种挑战。 一、一键生成统计二维码,告别繁琐填码 地推

Atcoder Beginner Contest 359

传送门 A - Count Takahashi 时间限制:2秒        内存限制:1024MB 分数:100分 问题描述 给定 N 个字符串。 第 i 个字符串  () 要么是 Takahashi 要么是 Aoki。 有多少个 i 使得  等于 Takahashi ? 限制 N 是整数。每个字符串  是 Takahashi 或者 Aoki。() 输入格式

吴恩达教程以及《统计学习方法》学习笔记

之前都在有道云笔记写的,CSDN不能上传文件,搬运过来实在比较耗费精力,在此给出分享链接: 1、吴恩达教程 2、统计学习方法