noip2018普及组初赛解析_NOIP复赛

noip2018普及组初赛解析_NOIP复赛博主是一个高中生,在进行noip训练的时候遇到这一题,当时写了2个多小时惭愧啊惭愧,只能感叹一声普及组好可怕!!!然而这题在code.vs里只有黄金。。。我现在很怀疑自己是怎么做出那些大师题的。。。原题链接在此:http://codevs.cn/problem/1133/好了,现在我们来分析一下这个题目。这个题目中读入的字符串是只有‘*’、‘+’、‘(‘和’)‘的,而

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

本题大意如下:

NOIP2011普及组——表达式的值

Description

对于1 位二进制变量定义两种运算:
运算规则
0 ⊕0=0
0 ⊕1=1
1 ⊕0=1
1 ⊕1=1
0 × 0=0
0 × 1=0
1 × 0=0
1 × 1=1
运算的优先级是:
1. 先计算括号内的,再计算括号外的。
2. “× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算。
例如:计算表达式A⊕B × C时,先计算 B × C,其结果再与 A 做⊕运算。 现给定一个未完成的表达式,例如+(_*),请你在横线处填入数字0 或者1 ,请问有多少种填法可以使得表达式的值为0 。

Input

第1 行为一个整数 L,表示给定的表达式中除去横线外的运算符和括号的个数。
第2行为一个字符串包含 L 个字符,其中只包含’(’、’)’、’+’、’’这4 种字符,其中’(’、’)’是左右括号,’+’、’’分别表示前面定义的运算符“⊕”和“×”。这行字符按顺序给出了给定表达式中除去变量外的运算符和括号。

Output

输出文件exp.out 共1 行。包含一个整数,即所有的方案数。注意:这个数可能会很大,请输出方案数对10007 取模后的结果。

Sample Input

4
+(*)

Sample Output

3

Data Size & Hint

给定的表达式包括横线字符之后为:+(_*)?
在横线位置填入(0 、0 、0) 、(0 、1 、0) 、(0 、0 、1) 时,表达式的值均为0 ,所以共有3种填法。?
【数据范围】
对于20% 的数据有 0 ≤ L ≤ 10。
对于50% 的数据有 0 ≤ L ≤ 1,000。
对于70% 的数据有 0 ≤ L ≤ 10,000 。
对于100%的数据有 0 ≤ L ≤ 100,000。
对于50% 的数据输入表达式中不含括号。

博主是一个逗逼的高中生,在进行noip训练的时候遇到这一题,当时写了2个多小时
惭愧啊惭愧,
只能感叹一声普及组好可怕!!!
然而这题在code.vs里只有黄金。。。
我现在很怀疑自己是怎么做出那些大师题的。。。
原题链接在此:
http://codevs.cn/problem/1133/
好了,现在我们来分析一下这个题目。
这个题目中读入的字符串是只有‘*’、‘+’、‘(‘和’)‘的,而左右括号是互相配对的,优先级最高。
因此我们可以在栈中加入左括号的位置,在遇见右括号的时候依次取出栈中的值即可
在计算时有意思的是这个式子中是没有数字的,原题只是需要计算填完数字后值为0的情况总数而已
这个时候一些码农同志们可能就会不考虑复杂度直接开敲
给各个位置都填上数值,最后check。。。
这种人我也是醉了,博主对此不作评价
而正常人在开敲每道题的代码之前总是会总结一些什么的
在这一道题中
如果我们把数对(a,b)当做一个数Si分别为为0、1的情况数
那么很容易可以得出:

  • (a,b)*(c,d)=(ac+bc+ad,bd);
  • (a,b)+(c,d)=(ac,bc+ad+bd);

知道了这个性质之后同志们就可以开始敲代码了,每次把括号中的值算好后储存在左括号的位置即可
需要注意的是循环中的下标的变化并能连续的,否则复杂度为O(n^2)会超时
这个时候就需要一点简单的小技巧了,每次计算完一个括号中的值时,将左括号的nxt指向右括号,保证不重复遍历某一子串。
而且这个解法如果使用c++数据库中的string可以简单很多,好吧,其实没啥区别
代码如下:

//PS:原题有特别说明,将结果mod10007
#include<string>
#include<vector>
#include<iostream>
using namespace std;
#define M 300005
#define P 10007
string str;
int pre[M],nxt[M];
struct node{
    int a,b;
    node init(){
  
  //初始化每个数为0或1的情况数
        a=1;b=1;
    }
}ans,res[M];
struct li{
    int l,r;
};
vector<li>edge;
void add(node &A,node B){
    node C;
    C.a=(A.a*B.a)%M;
    C.b=(A.a*B.b+A.b*B.a+A.b*B.b)%M;
    A=C;
}// 加法计算
void mul(node &A,node B){
    node C;
    C.a=(A.a*B.a+A.a*B.b+A.b*B.a)%M;
    C.b=A.b*B.b%M;
    A=C;
}//乘法运算
int main(){
    int n;
    cin>>n;
    cin>>str;
    str.insert(0," ");
    for(int i=0;i<str.length();i++)res[i].init();
    int top=0;
    for(int i=0;i<str.length();i++){
        if(str[i]=='(')pre[top++]=i;
        else if(str[i]==')'){
            int p=pre[--top],s=p,cnt=0;
            li tmp;
            tmp.l=p,tmp.r=i;
            edge.push_back(tmp);
        }//好吧,这里是博主智障了,其实完全可以再加上1层for直接计算括号中的值。
       //反正仍旧是O(n)复杂度
        //(其实这里是博主当初敲O(n^2)WA代码的时候想的优化,然而似乎并没有什么软用)
    }for(int i=0;i<str.length();i++)nxt[i]=i+1;
    for(int k=0;k<edge.size();k++){
        li tmp=edge[k];
        int p=tmp.l,i=tmp.r,s=p;
        for(int j=p+1;j<i;j=nxt[j])
            if(str[j]=='(')res[j-1]=res[j];//将括号中计算好的结果导出
        for(int j=p+1;j<i;j=nxt[j]){
            if(str[j]=='*')mul(res[s],res[j]);//先计算乘法
            else if(str[j]=='+')s=j;//若遇到加号,略过它,并且之后的乘法需要累加到这个加号上。。
                                        //这一点相信有点智商的小朋友都能明白
        //至于为什么要累加到加号上,这纯粹是因为博主不想在运算符之中插入一个个空格,影响式子的美感罢了
        }s=p;                                                      //(好吧,我承认我懒。。)
        for(int j=p+1;j<i;j=nxt[j])
            if(str[j]=='+')add(res[s],res[j]);//最后再进行加法运算
        nxt[p]=i;//将左括号的nxt指向右括号
    }
    //*
    for(int i=1;i<str.length();i=nxt[i])
        if(str[i]=='(')res[i-1]=res[i];
    int s=0;
    for(int i=1;i<str.length();i=nxt[i]){
        if(str[i]=='*')mul(res[s],res[i]);
        else if(str[i]=='+')s=i;
    }s=0;
    for(int i=1;i<str.length();i=nxt[i])
        if(str[i]=='+')add(res[s],res[i]);
        *//中间带注释的这一段你可以选择略过它,
     //因为这本就是博主一时懵逼敲的。。
    //后来才察觉,可以直接用string.insert往整个式子的开头和末尾在插入一对括号就行了。。。 
    cout<<res[0].a<<endl;
    return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/189734.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • php查询IP地址归属等信息

    淘宝公司提供了一个很好用的IP地理信息查询接口。在这里:http://ip.taobao.com/TaobaoIPQuery2这个类将极大的简化相关的信息查询。类TaobaoIPQuery2文件:

    2021年12月20日
  • 三大通信协议(二):IIC通信协议

    三大通信协议(二):IIC通信协议1.概念是什么?I²C(Inter-IntegratedCircuit),中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,是由飞利浦公司在1980年代初设计的,方便了主板、嵌入式系统或手机与周边设备组件之间的通讯。由于其简单性,它被广泛用于微控制器与传感器阵列,显示器,IoT设备,EEPROM等之间的通信。优点仅需要两条总线即可通讯(大大的节约了IO口资源)最大主机数量:无限制。最大从机限制:理论127(一个主机多个从机,一对多,多对一,多对多)2.硬件连

  • lcd电子时钟怎么调_keil液晶显示程序

    lcd电子时钟怎么调_keil液晶显示程序第11周上机程序-LCD12864显示-操作示范结果展示取模软件软件图片软件下载百度网盘下载钉钉群下载软件使用方法(文字取模)软件使用方法(字符取模)程序修改导入原本程序修改原程序修改文字修改学号完整程序结果展示取模软件软件图片软件下载百度网盘下载链接:link.提取码:houh钉钉群下载软件使用方法(文字取模)点击C51后字符便会自动生成。保存为记事本形式,如下所示软件使用方法(字符取模)一样的操作,输入学号,生成16进制数组,保存于桌面即可。程

  • stm32f4库函数开发指南 pdf_c语言常用的库函数表

    stm32f4库函数开发指南 pdf_c语言常用的库函数表资料介绍STM32F103库函数用户手册(中文)UM0427用户手册32位基于ARM微控制器STM32F101xx与STM32F103xx固件函数库介绍本手册介绍了32位基于ARM微控制器STM32F101x…

    2022年10月15日
  • The server does not support version 3.0 of the J2EE Web module specification

    The server does not support version 3.0 of the J2EE Web module specification

  • UICollectionView的单选

    UICollectionView的单选//点击选定-(void)collectionView:(UICollectionView*)collectionViewdidSelectItemAtIndexPath:(NSIndexPath*)indexPath{    JFCollectionViewCell*cell=(JFCollectionViewCell*)[collection

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号