省赛适应赛(二)

版权声明:《本文为博主原创文章,转载请注明出处。 》 https://blog.csdn.net/zbq_tt5/article/details/89714589

                                      计算器的改良

模拟题虐我千万遍`~~~zhaxinle。

这道题分为两个部分,等号前面的和等号右边的,在计算的时候等号前面的标记为flag=1,等号右边的标记为flag=1,不过操作的时候是减。

这个flag的作用是进行加减运算。

大思路就是定义两个变量num1,num2,分别代表的是常数的大小和带变量的数的系数的大小。

#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
char num[5000];
int main()
{
    int flag=1;
    char a;
    cin>>num;
    int  num1=0,num2=0,numm=0;
    int l1=strlen(num);
    int i;
    for(i=0;; ++i)
    {
        if(num[i]>='0'&&num[i]<='9')
        {
            numm=(10*numm+num[i]-'0');
        }
        else if(num[i]>='a'&&num[i]<='z')
        {
            a=num[i];
            num2+=numm*flag;
            numm=0;
        }
        else if(num[i]=='-')
        {
            num1+=flag*numm;
            flag=-1;
            numm=0;
        }
        else if(num[i]=='+')
        {
            num1+=flag*numm;
            flag=1;
            numm=0;
        }
        else if(num[i]=='=')
        {
            num1+=flag*numm;
            break;
        }
    }
    flag=1;
    numm=0;
    for(i; num[i]!='\0'; ++i)
    {
        if(num[i]>='0'&&num[i]<='9')
        {
            numm=(10*numm+num[i]-'0');
        }
        else if(num[i]>='a'&&num[i]<='z')
        {
            a=num[i];
            num2-=numm*flag;
            numm=0;
        }
        else if(num[i]=='-')
        {
            num1-=flag*numm;
            flag=-1;
            numm=0;
        }
        else if(num[i]=='+')
        {
            num1-=flag*numm;
            flag=1;
            numm=0;
        }
    }
    num1-=flag*numm;
    if(num2==0)
        printf("%c=0.000\n",a);
    else
    printf("%c=%.3lf\n",a,double(-num1)/num2);
    return 0;
}

                                              单词接龙

考察:搜索(dfs)

这个搜索寻找的是最长的串的长度,与此同时,我们还需要加上找到的这个字符串,那么我们搜索是在原有的基础之上进行的,所以在搜索的过程中,我们需要定义一个数组记录每一个字符串出现的次数(因为每一个字符串出现的次数不能超过两次)。

我认为判断某一个字符串是否应该在当前串的基础上加上去应该分为两种判断方式:

1、判断能不能加到这个串上

2、加到这个串上

判断能不能加上去的话,就要判断从1到字符长度中的一个k中(1到k范围内是否与给定的串的后k位一样)。

当然,加上这个字符串的操作是基于判断之上的,可以通过上面的解释推出来。

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
const int maxn=55;
int max_number,number[maxn];
int n;
string word[maxn];
int judge(string neew, string word,int j)
{
   int l=neew.size();
   for(int i=0;i<j;++i)
   {
       if(word[i]==neew[l-j+i])
       {
          continue;
       }
       else
        return 0;
   }
   return 1;
}

void add(string &neew, string word,int k,int l)
{
    for(int i=k;i<l;++i)
    {
        neew+=word[i];
    }
}

void dfs(string neew)
{
    int l1=neew.length();
    max_number=max(max_number,l1);
    for(int i=1; i<=n; ++i)
    {
        if(number[i]>=2)
            continue;
        int lll=word[i].length();
        for(int j=1; j<=word[i].length(); ++j)
        {
            if(judge(neew,word[i],j))
            {
                //判断后能接上
                 string temp=neew;
                 //别忘了复制,因为这里有可能不是最优解
                add(temp,word[i],j,lll);
                if(temp==neew) continue;
                number[i]++;
                dfs(temp);
                number[i]--;
                break;
                //别忘了huanyuan
            }
            //如果不能接上就 pass
        }
    }
}

int main()
{
    cin>>n;
    for(int i=1; i<=n; ++i)
        cin>>word[i];
    //现在输入要拼接的单词,但是不知道长度
    //在接下来的运算中 还要计算它的长度
    string beginn;
    cin>>beginn;
    dfs(beginn);
    printf("%d\n",max_number);
    return 0;
}

推荐博客:https://blog.csdn.net/Loi_Shirley/article/details/52234721

                                       借教室

1.线段树

区间更新,判断节点权值是否小于0

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<vector>
#include<string>
using namespace std;
const int maxn=1000005;
int i,n,m,treemin[maxn<<2],lazy[maxn<<2],a[maxn];
bool flag=true;

void push_up(int rt)
{
    treemin[rt]=min(treemin[rt<<1],treemin[rt<<1|1]);
    return ;
}

void build(int rt,int l,int r)
{
    if(l==r)
    {
        treemin[rt]=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    push_up(rt);
    return ;
}

void push_down(int rt, int num)
{
    treemin[rt<<1]+=lazy[rt];
    lazy[rt<<1]+=lazy[rt];

    treemin[rt<<1|1]+=lazy[rt];
    lazy[rt<<1|1]+=lazy[rt];

    lazy[rt]=0;
    return ;
}

void update(int L,int R,int delta,int num,int l, int r)
{
    if(flag)//根据题意进行标记
    {
        if(L<=l&&r<=R)
        {
            lazy[num]+=delta;
            treemin[num]+=delta;
            if(treemin[num]<0)
            {
                printf("-1\n%d\n",i);
                flag=false;
            }
            return ;
        }
        if(lazy[num])
        {
            push_down(num,r-l+1);
        }
        int mid=(l+r)>>1;
        if(L<=mid)
            update(L,R,delta,num<<1,l,mid);
        if(R>mid)
            update(L,R,delta,num<<1|1,mid+1,r);
        push_up(num);
        return ;
    }
}
int read()//快读
{
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}
int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);//加速输入输出流
//    cin>>n>>m;
    n=read();
    m=read();
    for(int i=1;i<=n;++i)
       a[i]=read();
    build(1,1,n);
    for( i=1;i<=m;++i)
    {
        int val,l,r;
//        cin>>val>>l>>r;
        val=read();
        l=read();
        r=read();
        update(l,r,-val,1,1,n);
    }
    if(flag)
        printf("0\n");
    return 0;
}

2.差分加二分

刚接触的时候,感觉特别像前缀和,每一次进行一个判断,判断当前长度是否成立,在长度为m的时候如果成立的话就输出0,反之我们要使用二分的方法寻找最合适的答案。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
int a[maxn],value[maxn],lef[maxn],righ[maxn];
int num[maxn];
int n,m;
int judge(int x)
{
    memset(num,0,sizeof(num));
    for(int i=1;i<=x;++i)
    {
        num[lef[i]]+=value[i];
        num[righ[i]+1]-=value[i];
    }
    for(int i=1;i<=n;++i)
    {
        num[i]+=num[i-1];
        if(num[i]>a[i])
            return 0;
    }
    return 1;
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;++i)
        cin>>a[i];
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&value[i],&lef[i],&righ[i]);
    }
    if(judge(m))
    {
        printf("0\n");
        return 0;
    }
    int l=1,r=m;
    while(l<r)
    {
       int mid=(l+r)/2;
       if(judge(mid))
       {
           l=mid+1;
       }
       else
       {
           r=mid;
       }
    }
    printf("-1\n%d\n",r);
    return 0;
}

                                                售票

这道题,使用了C上面的strncmp函数,这个函数包含三部分,字符串A,字符串B,整数C,意思就是说,如果现在A和B的前C位的相同的话,就返回0.

那么可以通过逆向思维,假设一开始输出的全是‘*’,把符合条件的字符加进去就OK了

#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
const int maxn=105;
char putss[]={"********\n********\n********\n********"};
int main()
{
    int n;
    char word[maxn][maxn];
    cin>>n;
    for(int i=1;i<=n;++i)
        cin>>word[i];
    char a[maxn];
    cin>>a;
    int l1=strlen(a);
    for(int i=1;i<=n;++i)
    {
        if(!strncmp(word[i],a,l1))
        {
            char c=word[i][l1];
            if(c>='A'&&c<='E')
                putss[c-'A'+3]=c;
            if(c>='F'&&c<='M')
                putss[c-'A'+4]=c;
            if(c>='N'&&c<='U')
                putss[c-'A'+5]=c;
            if(c>='V'&&c<='Z')
                putss[c-'A'+6]=c;
        }
    }
    cout<<putss;
    return 0;
}

                                             Vigenère密码

题意:给出两个字符串,第一个代表的是秘钥,第二个代表的是加密后的密文,现在通过这两个字符串找出所对应的明文,寻找的方法由图可以看出来

我们发现对于每一行的数字,假设A代表1,Z代表的是26的话,ZA对应的是26-1+1,也就是Z(26),ZB对应的是26+2-1,这个及果实27,要对其取余(%26),结果为1,对应的字母就应该是A!

题目中有给出限制条件:

1. ®运算忽略参与运算的字母的大小写,并保持字母在明文M中的大小写形式; 

2. 当明文M的长度大于密钥k的长度时,将密钥k重复使用。

首先,我们输出的有大写字母,有小写字母,不过输出大小写是通过数组b判断的

字符->ASCII,那么我们找到一个参考系,把这两个字符全部转化到这个上来

#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
string a,b;
int main()
{
    cin>>a>>b;
    int l1=a.size();
    int l2=b.size();
    for(int i=0; i<l2; ++i)
    {
        if(a[i%l1]>='A'&&a[i%l1]<='Z')
            a[i%l1]+=32;
        if(b[i]>='A'&&b[i]<='Z')
        {
            printf("%c",(b[i]-'A'-(a[i%l1]-'a')+26)%26+'A');
        }
        else
        {
            printf("%c",(b[i]-'a'-(a[i%l1]-'a')+26)%26+'a');
        }
    }
    printf("\n");
    return 0;
}

                                                     

                                                  摆花

考察:动态规划

行代表的是花的种数,列代表的是需要摆放的花的数量。

那么首先分析第一行,代表的是现在有0种花,如果说我们要摆放0盆花的话,有一种情况,其他的有0种情况。

同理,对于每一列的第一行,所有的情况都应该是1

现在看(1,1),代表的是1种花,要摆放1盆花,这个时候我们知道a[1],a[2]都是大于1的,那么(1,1)=2;

注意看这里的过程,我们对a[1]和a[2]都进行了一个比较,没看出来规律,先不要着急,看下面的一个分析

现在看(2,2),代表我们现在有两种花,要摆放两盆花,当然,这两种花的数量分别是3和2,如果各自摆放上去的话,其实都是成立的,那现在就是说,还有一种情况就是两种花各有一盆,那么就又多了一个需要考虑的地方,也就是说,我们现在对于一盆花从1到a[i]摆放,其他的没有摆放的花放其他的花,在动态规划的过程中,我们知道,前面的情况是很复杂的,所以我们可以直接加上前面算过的结果,也就是:

dp[i][j]=(dp[i][j]+dp[i-1][j-k])%1000007;

#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
const int maxn=105;
int dp[maxn][maxn];
int a[maxn];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1; i<=n; ++i)
        cin>>a[i];
    for(int i=1; i<=m; ++i)
        dp[0][i]=0;
    for(int i=0; i<=n; ++i)
        dp[i][0]=1;
    for(int i=1; i<=n; ++i)
    {
        for(int j=1; j<=m; ++j)
        {
            for(int k=0; k<=a[i]; ++k)
            {
                if(j>=k)
                    dp[i][j]=(dp[i][j]+dp[i-1][j-k])%1000007;
            }
        }
    }
    printf("%d\n",dp[n][m]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zbq_tt5/article/details/89714589
今日推荐