洛谷 P1371 NOI元丹
来源:互联网 发布:windows 10碎片整理 编辑:程序博客网 时间:2024/04/28 03:33
题目描述
小A打算开始炼NOI元丹(什么鬼),据说吃了可以提高NOI时的成绩。
是这么练的。元丹有三种元核,’N’,’O’,’I’。现有很多个这样原核,按顺序排成一行。炼元丹时,从左往右分别挑出’N’,’O’,’I’三个原核吞下。
现在他关心,有几种服用方式……且慢!
他觉得服用方式太少,以至于不能成仙。所以他可以通过某个途径,得到’N’,’O’,’I’的三种原核中的任意一个,至于哪一种由他决定。然后他将获得这个原核的插入到这一排原核中的任意位置(包括最前最后)。
现在你要知道,新的元核序列中能有多少种’N’,’O’,’I’的取出方式。子串的字母并不要求连续。
输入输出格式
输入格式:
第一行,一个整数N,表示字符串的长度。
第二行,一行字符串,里面只有只有’N’,’O’,’I’三种字母。
输出格式:
表示出最多可以提炼出来的NOI元丹的方案种数。
输入输出样例
输入样例#1:
5
NOIOI
输出样例#1:
6
说明
样例解释
他可以获取一个N元核,加到最前面。
NNOIOI | NNOIOI | NNOIOI | NNOIOI | NNOIOI | NNOIOI
~ ~~ | ~ ~ ~ | ~ ~~ | ~~~ | ~~ ~ | ~ ~~
30%的数据N<=200
50%的数据N<=2000
100%的数据3<=N<=100000
【分析】
无敌前缀和!乱搞一番!
这题我拿后缀和做的…其实跟前缀和貌似没有差别呢。
对于增加N,肯定放在第一个之前最棒
对于I,最后一个位置最棒
对于O,枚举一波,每次枚举复杂度O(1),具体求法就是在该位置之前的N的个数乘该位置之后的I的个数。
代码略长了些…考试嘛…脑子比较迷糊…
【代码】
//洛谷月赛 2.NOI元丹 #include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define ll long long#define M(a) memset(a,0,sizeof a)#define fo(i,j,k) for(i=j;i<=k;i++)using namespace std;const int mxn=100005;char s[mxn];ll n,now,ans=0,ans1,ans2,ans3;ll next[mxn],sum_o[mxn],sum_i[mxn],sum_n[mxn],res[mxn];int main(){ /////读入////// int i,j,h; scanf("%lld",&n); scanf("%s",s+1); now=n+1; /////初始化////// for(i=n;i>=1;i--) { sum_o[i]=sum_o[i+1]; sum_i[i]=sum_i[i+1]; sum_n[i]=sum_n[i+1]; if(s[i]=='N') { sum_n[i]++; next[i]=now; now=i; } else if(s[i]=='O') sum_o[i]++; else sum_i[i]++; } /////////getN//////// for(i=n;i>=1;i--) if(s[i]=='N') { int tmp=next[i]; res[i]=res[tmp]; tmp--; fo(j,i+1,tmp) if(s[j]=='O') res[i]+=sum_i[j]; ans+=res[i]; }// printf("pre=%d\n",ans); ans1=ans; {//'N' fo(i,1,n) if(s[i]=='N') {h=i;break;} ans1+=res[h]; fo(j,1,h) if(s[j]=='O') ans1+=sum_i[j]; }////////////////////////////////////////无敌分割线->getI now=0; fo(i,1,n) if(s[i]=='I') next[i]=now,now=i; M(res); fo(i,1,n) if(s[i]=='I') { int tmp=next[i]; res[i]=res[tmp]; tmp++; fo(j,tmp,i) if(s[j]=='O') res[i]+=sum_n[1]-sum_n[j]; } {//'I' for(i=n;i>=1;i--) if(s[i]=='I') {h=i;break;} ans2+=res[h]; for(j=n;j>h;j--) if(s[j]=='O') ans2+=sum_n[1]-sum_n[j]; } ans2+=ans; ///////////////getO//////////// fo(i,1,n) ans3=max(ans3,ans+(sum_n[1]-sum_n[i+1])*sum_i[i]);// printf("N=%lld\nO=%lld\nI=%lld\n",ans1,ans3,ans2); ans=max(ans1,max(ans2,ans3)); printf("%lld\n",ans); return 0;}
- 洛谷 P1371 NOI元丹
- 洛谷 P1371 NOI元丹
- 洛谷 P1371 NOI元丹
- 洛谷P1371 NOI元丹
- 【洛谷 P1371】NOI元丹(枚举+乱搞)
- 洛谷1371 NOI元丹
- 【前缀和】 洛谷1371 NOI元丹
- NOI元丹
- NOI
- [BZOJ 3240][NOI 2013]矩阵游戏(数学+乘法逆元)
- NOI 2015 d1t2 洛谷 【P2146】 软件包管理器
- 洛谷 P3825 游戏[NOI 2017] (2-SAT)
- Tyvj p1371 蛇灵迷宫 (博弈 输出路径)
- 【题解】洛谷1047 校门外的树(NOI…
- 洛谷 P1801 [NOI导刊2010提高(06)] 黑匣子
- #洛谷 P1958 上学路线 [DFS-图的遍历-NOI导刊]
- NOI web
- NOI 2010
- Linux下如何修改用户默认目录
- Qt实现环形缓冲区的两种方法
- 关于一些常见bug
- ubuntu, 解决Mysql root登录出错: ERROR 1045 (28000)
- 近期阅读
- 洛谷 P1371 NOI元丹
- 16.jquery ajax与html
- 自定义toolbar标题栏
- cocos2dx-3.12 解决点击空白不触发editBoxReturn事件
- 大规模数据爬取(BeautifulSoup)
- C4.5分类树
- 万能适配器
- 二维数组的使用
- Java web 中关于Servlet的一些总结