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)


相关推荐

发表回复

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

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