• NOIP赛前模拟20171027总结


    题目:

    1.寿司

      给定一个环形的RB串··要求经过两两互换后RB分别形成两段连续区域,求最少操作次数(算法时间O(n))

    2.金字塔

      给定一个金字塔的侧面图有n层··已知每一层的宽度··高度均为1··要求在图中取出恰好K个互不相交的矩形(边缘可以重叠),求最多可以取出多少面积

      n<=20000,k<=100

    3.心灵治愈

      给定n,m要求取出不大于m的n个正整数,问有多少种取法使n个数和m的最大公因数为1,n,m<=10^15

    题解:

    1.分析

      首先为了方便我们把环从中间断开看成一个序列,我们考虑如果移动R串··那么肯定是找到某一B为中心··B的左边R移到一起··B的右边R移到一起(这里描述有点模糊···如果序列左边的R都移到一起,且序列最左边为R,右边同理··则实际在环中R肯定是连续的一段··)

      因此我们先随意找一个B为中心··然后计算答案··之后我们一次将序列最左端的字符移到最右端(比如序列BBRRR移动后就变成BRRRB)然后考虑答案的变化即可···具体实现参见代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int N=2e6+5;
    int T,n,num[N];
    char s[N];
    int main()
    {
      //freopen("a.in","r",stdin);
      //freopen("a.out","w",stdout);
      scanf("%d",&T);
      while(T--)
      {
        long long ans=0,cnt=0;
        int tot1=0,tot2=0,totl=0,totr=0,mid;
        scanf("%s",s+1);n=strlen(s+1);
        for(int i=1;i<=n;i++)
        {
          if(s[i]=='B')  num[i]=num[i+n]=1,tot1++;
          else num[i]=num[i+n]=2,tot2++;
        }
        int half=(tot1+1)/2;int temp=0;
        for(int i=1;i<=n;i++)
        {
          if(num[i]==1)  {temp++;if(temp==half)  mid=i;}
          else
          {
            if(temp<half){totl++;cnt+=temp;}
            else {totr++;cnt+=(tot1-temp);}
          }
        }
        ans=cnt;
        for(int i=1;i<n;i++)
        {
          if(num[i]==1)
          { 
            int tot=0,j;
            for(j=mid+1;num[j]!=1;j++)  tot++;    
            cnt-=totl;cnt+=(totr-tot);mid=j;
            totl+=tot;totr-=tot;
            if(tot1%2==0) cnt-=tot;
            ans=min(ans,cnt);
          }
          else 
          {
            totl-=1;totr+=1;  
          }
        }
        cout<<ans<<endl;
      }
      return 0;
    }

    2.dp+决策单调性/斜率优化

      dp方程肯定很好想··第一要明确取的方案··我们肯定是以某一层的宽度为矩形的一边··然后往下取到某一层为一个矩形·矩形的高就是两层高的差··

      然后设f[j][i]为第j块矩形以第i层为一边的最大面积··转移方程即为:

      f[j][i]=max(f[j][i],f[k][i-1]+(long long)len[j]*(j-k));

      其中k为我们往下枚举的层数··len为j层的宽度··

      然后通过打表(dalao也可以分析)得出该方程满足决策单调性且使用于斜率优化····这里两种方法都能过

      决策单调性:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<string>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int R()
    {
      char c;int f=0;
      for(c=getchar();c<'0'||c>'9';c=getchar());
      for(;c<='9'&&c>='0';c=getchar())  f=(f<<3)+(f<<1)+c-'0';
      return f;
    }
    const int N=20005;
    const int M=105;
    struct node
    {
      int l,r,pos;
    }Que[N];
    int n,K;
    long long len[N],f[N][M];
    inline long long calc(int i,int j,int now)
    {
      return f[j][now-1]+(long long)len[i]*(i-j);
    }
    inline int find(node a,int b,int now)
    {
      int le=a.l,ri=a.r,ans=a.r+1;
      while(le<=ri)
      {
        int mid=(le+ri)/2;
        if(calc(mid,b,now)>calc(mid,a.pos,now))  ri=mid-1,ans=mid;
        else le=mid+1;
      }
      return ans;
    }
    inline void dp(int now)
    {
      int Head=1,Tail=0;
      node tmp;tmp.l=now;tmp.r=n;tmp.pos=now-1;Que[++Tail]=tmp;
      for(int i=now;i<=n;i++)
      {
        while(Que[Head].r<i)  Head++;
        f[i][now]=calc(i,Que[Head].pos,now);
        if(calc(n,i,now)>calc(n,Que[Tail].pos,now))
        {
          while(Head<=Tail&&calc(Que[Tail].l,i,now)>calc(Que[Tail].l,Que[Tail].pos,now))  Tail--;
          if(Head<=Tail)
          {
            int t=find(Que[Tail],i,now);
            Que[Tail].r=t-1;
            node tmp;tmp.l=t,tmp.r=n,tmp.pos=i;Que[++Tail]=tmp;
          }
          else
          {
            node tmp;tmp.l=i+1;tmp.r=n;tmp.pos=i;Que[++Tail]=tmp;
          }
        }
      }
    }
    int main()
    {
      //freopen("pyramid.out","w",stdout);
      n=R(),K=R();int x,y;
      if(n<=1000)
      {  
        for(int i=1;i<=n;i++)
        {
          x=R(),y=R();len[i]=y-x+1;f[i][1]=(long long)len[i]*i;
        }
        for(int i=2;i<=K;i++)
          for(int j=i;j<=n;j++)
            for(int k=i-1;k<j;k++)  f[j][i]=max(f[j][i],f[k][i-1]+(long long)len[j]*(j-k));
        long long ans=0;
        for(int i=K;i<=n;i++)  ans=max(f[i][K],ans);
        cout<<ans<<"
    ";
      }
      else
      {
        for(int i=1;i<=n;i++)
        {
          x=R(),y=R();len[i]=y-x+1;f[i][1]=(long long)len[i]*i;
        }
        for(int i=2;i<=K;i++)
          dp(i);
        long long ans=0;
        for(int i=K;i<=n;i++)  ans=max(f[i][K],ans);   
        cout<<ans<<"
    ";
      }
      return 0;
    }

    3.质因数分解+容斥原理

      这道题和之前跳蚤的那道题是一模一样的··这里就并不多说了··

      唯一注意的是我发现了自己快速幂的一个漏洞··求a^b之前要将a取模···之前一直没有注意到···还有就是注意最后答案为负的问题

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<vector>
    using namespace std;
    vector<long long>zhiyinzi;
    const long long mod=1e9+7;
    long long n,m,ans=0;
    inline long long ksm(long long a,long long b)
    {
      long long ans=1;a%=mod;  
      while(b)
      {
        if(b%2==1)  ans=(ans*a)%mod;
        b/=2;a=(a*a)%mod;
      }
      return ans;
    }
    inline void dfs(int u,long long tot,long long f)
    {
      if(u==zhiyinzi.size())
      {
        long long temp=m/tot;
        ans=(ans+f*ksm(temp,n))%mod;
        ans=(ans%mod+mod)%mod;
        return;
      }
      dfs(u+1,tot,f);
      dfs(u+1,tot*zhiyinzi[u],-f);
    }
    int main()
    {
      scanf("%I64d%I64d",&n,&m);
      long long temp=m;
      for(long long i=2;i*i<=m;i++)
      {
        if(i>temp)  break;  
        if(temp%i==0)
        { 
          while(temp%i==0)  temp/=i;
          zhiyinzi.push_back(i);
        }
      }
      if(temp!=1)  zhiyinzi.push_back(temp);
      dfs(0,1,1);
      ans=(ans%mod+mod)%mod;
      cout<<ans<<endl;
      return 0;
    }

      

  • 相关阅读:
    hdu5714 拍照[2016百度之星复赛C题]
    hdu5715 XOR 游戏 [2016百度之星复赛D题]
    AFO
    BZOJ 3566 概率充电器
    BZOJ 3427 Bytecomputer
    BZOJ 4513 储能表
    BZOJ 3667 Miller_Rabin
    BZOJ 4557 侦察守卫
    BZOJ 3894 文理分科
    SUOI #69 奔跑的Aqua
  • 原文地址:https://www.cnblogs.com/AseanA/p/7745338.html
Copyright © 2020-2023  润新知