zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第三场)

    传送门

    B.Crazy Binary String(前缀和)

    •题意

      给你一个只包含 0,1 的串 s;

      求满足 0 与 1 的个数相同的子串和子序列;

      输出这两个串的最大长度;

    •思路

    找01个数相同的子串,类似于这个(A题),(话说比那个简单有没有

    根据前缀和求增量,如果增量相同的话,那这段区间里01个数就相同,然后每次取最大的ans

    找01个数相同的子序列,那肯定是01中个数少的那个所组成的,输出两倍就好了

    •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 map<int,int> mp;
     4 char s[10005];
     5 int zero,one;
     6 int ans;
     7 int main()
     8 {
     9     int n;
    10     cin>>n;
    11     mp[0]=0;
    12     for(int i=1;i<=n;i++)
    13     {
    14         cin>>s[i];
    15         if(s[i]=='0')
    16             zero++;
    17         else
    18             one++;
    19         if(mp.count(zero-one))
    20             ans=max(ans,i-mp[zero-one]);
    21         else
    22             mp[zero-one]=i;
    23     }
    24     cout<<ans<<' '<<min(zero,one)*2<<endl;
    25 }
    View Code

     

    D.Big Integer(数论)

    •题意

    $A_{n}=underbrace{1......1}_{n}$

    $A_{i^j}$ ≡ 0 (mod p)的个数,其中 1 ≤ i ≤ n , 1 ≤ j ≤ m;

    •思路

    写起来有点麻烦...具体戳这里

    防止忘记推导过程,记一下重点...

    •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 int p,n,m;
     5 ll ans;
     6 int P[105];
     7 int x[105];
     8 
     9 ll qpow(ll a,ll b,ll mod)
    10 {
    11     ll res=1;
    12     while(b)
    13     {
    14         if(b&1)
    15             res=res*a%mod;
    16         a=a*a%mod;
    17         b>>=1;
    18     }
    19     return res;
    20 }
    21 
    22 int F()//因子分解得到最小循环节d,Max(d)=p-1
    23 {
    24     int d=p-1;
    25     for(int i=1;i*i<=p-1;i++)
    26     {
    27         if((p-1)%i==0)
    28         {
    29             if(qpow(10,i,p)==1)
    30                 d=min(d,i);
    31             if(qpow(10,(p-1)/i,p)==1)
    32                 d=min(d,(p-1)/i);
    33         }
    34     }
    35     return d;
    36 }
    37 
    38 int PrimeF(int d)//质因子分解 得到pi,xi,k
    39 {
    40     int k=0;
    41     for(int i=2;i*i<=d;i++)
    42     {
    43         if(d%i==0)
    44         {
    45             P[++k]=i;
    46             x[k]=0;
    47         }
    48         while(d%i==0)
    49         {
    50             x[k]++;
    51             d/=i;
    52         }
    53     }
    54     if(d!=1)
    55     {
    56         P[++k]=d;
    57         x[k]=1;
    58     }
    59     return k;
    60 }
    61 
    62 void Slove()
    63 {
    64     int d=F();
    65     int k=PrimeF(d);
    66     int maxX=*max_element(x+1,x+1+k);
    67     for(int j=1;j<=m;j++)//固定j,求个数
    68     {
    69         ll g=1;
    70         for(int i=1;i<=k;i++)
    71             g*=qpow(P[i],(x[i]+j-1)/j,p);  //p^(x+j-1)/j
    72         ans+=n/g;
    73 
    74         if(j>=maxX)//此时g为最小不再变化,共有(n/g)*(m-j)种
    75         {
    76             ans+=n/g*(m-j);
    77             break;
    78         }
    79     }
    80 }
    81 
    82 int main()
    83 {
    84     int t;
    85     cin>>t;
    86     while(t--)
    87     {
    88         cin>>p>>n>>m;
    89         ans=0;
    90         if(p==3)
    91             ans=n/3*m;
    92         else if(p==2||p==5)
    93             ans=0;
    94         else
    95             Slove();
    96         cout<<ans<<endl;
    97     }
    98 }
    View Code

     

    F.Planting Trees(单调队列优化)

    •题意

      在一块 n×n 的土地上植树;

      第(i,j) 块有棵高为 a[ i ][ j ] 树;

      必须要找一片满足任意两棵树的高度差都不超过 m 的矩形区域;

      并且想要这个矩形区域面积尽可能大;

      求出这个矩形区域,输出这个矩形区域包含的树的个数;

    •思路

    注意:

    单调队列代码实现时

    ①要分清楚值和索引,蟹蟹可爱的猪猪帮我找bug,此致敬礼!

    ②在出队列时(head++时)要注意队列非空,借鉴猪猪的经验!

    •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=505;
     4 int a[maxn][maxn];
     5 int demin[maxn];
     6 int demax[maxn];
     7 int Min[maxn];
     8 int Max[maxn];
     9 int n,m;
    10 int ans;
    11 
    12 int main()
    13 {
    14     int t;
    15     cin>>t;
    16     while(t--)
    17     {
    18         cin>>n>>m;
    19         ans=0;
    20         for(int i=1;i<=n;i++)
    21             for(int j=1;j<=n;j++)
    22                 cin>>a[i][j];
    23 
    24 
    25         for(int i=1;i<=n;i++)
    26         {
    27             //初始化
    28             for(int j=1;j<=n;j++)
    29                 Min[j]=Max[j]=a[i][j];
    30 
    31             //枚举上下边界
    32             //从第i行到第k行求最优解
    33             for(int k=i;k<=n;k++)
    34             {
    35                 for(int j=1;j<=n;j++)
    36                 {
    37                     //维护当前上下边界第i到第k行 每列的最大值最小值
    38                     Min[j]=min(Min[j],a[k][j]);
    39                     Max[j]=max(Max[j],a[k][j]);
    40                 }
    41 
    42                 int l=1,r=1;
    43                 int headmin=1,headmax=1;
    44                 int tailmin=0,tailmax=0;
    45                 //枚举右边界r
    46                 //维护两个单调队列
    47                 while(r<=n)
    48                 {
    49                     //单调递增队列,头是最小值
    50                     while(headmin<=tailmin&&Min[demin[tailmin]]>=Min[r])
    51                         tailmin--;
    52                     demin[++tailmin]=r;
    53                     //单调递减队列,头是最大值
    54                     while(headmax<=tailmax&&Max[demax[tailmax]]<=Max[r])
    55                         tailmax--;
    56                     demax[++tailmax]=r;
    57                     
    58                     //每个右边界确定后(也就是在此右边界下)
    59                     //找符合条件并使面积尽量大的左边界
    60                     while(l<=r&&Max[demax[headmax]]-Min[demin[headmin]]>m)
    61                     {
    62                         l++;
    63                         while(headmax<=tailmax&&demax[headmax]<l)
    64                             headmax++;
    65                         while(headmin<=tailmin&&demin[headmin]<l)
    66                             headmin++;
    67                     }
    68                     ans=max(ans,(r-l+1)*(k-i+1));
    69                     r++;//枚举下一个右边界 找最大值
    70                 }
    71             }
    72         }
    73         cout<<ans<<endl;
    74     }
    75 }
    View Code

    G.Removing Stones(假博弈 思维?)

    •题意

    有n堆石头,如果石头总数是奇数的话,就从最小堆中拿走一块

    如果总数是偶数堆或者是减少石头后,那每次从不为0的任意两堆中同时拿走一块

    如果最后都拿完,则Mark胜利

    现在给出每堆石头数,问存在多少对[l,r]使得可以有优胜情况

    •思路

    可以想一种极端情况,所有的堆都和最大的一堆一起拿

    那最大的一堆个数就是除本身以外所有堆的和

    通常情况就是其他堆之间也可以一起拿,

    那这个问题就转化成了

    有多少个区间使得在这个区间里,最大的堆<=其他堆的和

    貌似不太好找...但是!有一句话叫做正难则反!

    那我们可以用所有的情况-不符合的情况_(:з」∠)_

    那怎么找不符合的情况呢?

    我们可以通过枚举每一个堆 i,以这个堆为最大堆

    利用 最大的堆>其他堆的和,找到极限左边界,

    然后枚举左边界,通过固定的左边界L,找到右边界R

    那这个左边界L所构成情况就是 L—i,L—i+1...... L—R

    也就是每个L都有(R-i+1)种不符合的情况

    •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 #define N 300005
     5 ll T,n,m;
     6 ll a[N];
     7 
     8 int main()
     9 {
    10     cin>>T;
    11     while(T--)
    12     {
    13         cin>>n;
    14         ll ans=(ll)n*(n+1)/2;
    15         for(ll i=1;i<=n;i++)
    16             cin>>a[i];
    17         for(ll i=1;i<=n;i++)//枚举堆i
    18         {
    19             ll l=i,r=i,sum=0;
    20             while(l>1&&a[i]>sum+a[l-1])   //对于每一个a[i],找符合条件的最左边界
    21                 l--,sum+=a[l];
    22 
    23             for(int L=l;L<=i;L++)         //枚举L
    24             {
    25                 while(r<n&&a[i]>sum+a[r+1])//固定L,找到最右边界的
    26                     r++,sum+=a[r];
    27 
    28                 ans-=(r-i+1);//减去由L与i及其右边组成的
    29                 sum-=a[L];
    30             }
    31         }
    32         cout<<ans<<endl;
    33     }
    34 }
    View Code

    H.Magic Line(思维)

    •题意

            给你 n 个点,满足 n 为偶数,并且这 n 个为不重复的整数点;

      求将这 n 个点均分为两部分的直线 L,即有 n/2 个点严格在 L 上方,n/2个点严格在 L 下方;

      输出 L 上的任意两个点 (x1,y1),(x2,y2) 的坐标;

      要 x1,y1,x2,y2 为整数,且 |x1|,|y1|,|x2|,|y2| ≤ 109;

    •思路

    看到这个题,我第一反应是分蛋糕的题

    但是他不是!

    然后...然后就game over了

    用出题人的话来说就是

    假设没有x重复,可以按x排序,然后在中间画一条线

    现在有x重复,可以按照(x,y)双关键字排序,在中间偏左和中间偏右的两个中间点之间,画一条稍微稍微倾斜的线

    两种实现方式的具体细节在代码中解释

    •代码

    实现方式一

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int inf=1e8+5;
     4 struct node
     5 {
     6     int x,y;
     7 }s[1005];
     8 
     9 bool cmp(node a,node b)
    10 {
    11     if(a.x==b.x)
    12         return a.y<b.y;
    13     return a.x<b.x;
    14 }
    15 
    16 int main()
    17 {
    18     int t;
    19     cin>>t;
    20     while(t--)
    21     {
    22         int n;
    23         cin>>n;
    24         for(int i=1;i<=n;i++)
    25             cin>>s[i].x>>s[i].y;
    26         sort(s+1,s+1+n,cmp);
    27         int x1=s[n/2].x-1;
    28         int x2=s[n/2+1].x+1;
    29         int y1=s[n/2].y+inf;
    30         int y2=s[n/2+1].y-inf;
    31         cout<<x1<<' '<<y1<<' '<<x2<<' '<<y2<<endl;
    32         //①为什么要±1
    33         //稍微倾斜一下,并且保证不能有交点
    34         //x±(0,1],又因为是整数,x±1
    35               
    36         //②为什么是inf
    37         //y变化的很大,x变化的很小,这条线及其接近于竖直
    38         //才是稍微稍微倾斜一下
    39         
    40         //③为什么是±inf
    41         //y±相同的数,使得中间两个点这关于条线对称
    42         //正好分成左右两个部分使得左右的点个数相同
    43     }
    44 }
    View Code

    实现方式二

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int maxn=1e8+5;
     5 struct node
     6 {
     7     int x,y;
     8 }s[maxn];
     9 bool cmp(node a,node b)
    10 {
    11     if(a.x==b.x)
    12         return a.y<b.y;
    13     return a.x<b.x;
    14 }
    15 
    16 int t;
    17 int main()
    18 {
    19     cin>>t;
    20     while(t--)
    21     {
    22         int n;
    23         cin>>n;
    24         for(int i=1;i<=n;i++)
    25             cin>>s[i].x>>s[i].y;
    26         sort(s+1,s+n+1,cmp);
    27         int xx=s[n/2].x;
    28         int yy=s[n/2].y;
    29         cout<<xx-1<<' '<<yy+maxn<<' '<<xx+1<<' '<<yy-maxn+1<<endl;
    30         //①为什么要±1
    31         //稍微倾斜一下,并且保证不能有交点
    32         //x±(0,1],又因为是整数,x±1
    33         
    34         //②为什么要是inf
    35         //y变化的很大,x变化的很小,这条线及其接近于竖直
    36         //才是稍微稍微倾斜一下
    37         
    38         //③为什么是±inf
    39         //y±相同的数,使得中间两个点这关于条线对称
    40         //正好分成左右两个部分使得左右的点个数相同
    41         
    42         //④为什么y要+1
    43         //中间可能有整点,为了防止对称的时候过中间的整点y+1
    44         //为什么是+1,因为x2-x1>=2,当x2-x1=2时,k=y2-y1+2/x2-x1=(y2-y1/x2-x1)+1
    45         //可能过整点,就可能相交!
    46     }
    47 }
    View Code

    J.LRU management(模拟 unordered_map+list)

    •题意

    一个固定长度的LRU数组,每次有两种操作

    0号操作:若查询的字符串在数组中存在,就把它取出来,并原有值保持不变,压入数组末尾。

          若查询的字符串不存在则直接加入到末尾,值为输入的v。

          输出此字符串的值v

    1号操作:先得出输入的字符串在数组中的下标k,查询下标为(k+v)的数组元素的值,

          若k或(k+v)不存在都输出Invalid。

    •思路

    用unordered_map<string,list<>::iterator>来模拟

    不会这两个函数的可以先去看下用法....

    注意用cout时换行用endl会TLE,改成' '就会AC,时间快的还很多

    以前都不知道endl这么费时间_(:з」∠)_

    •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 struct Node
     4 {
     5     string ss;
     6     int v;
     7 };
     8 list<Node> l;
     9 unordered_map<string,list<Node>::iterator> mp;
    10 
    11 int main()
    12 {
    13     std::ios::sync_with_stdio(false),cin.tie(0);
    14     int t;;
    15     cin>>t;
    16     while(t--)
    17     {
    18         int n,m;
    19         cin>>n>>m;
    20         int op,v;
    21         string s;
    22         mp.clear(),l.clear();
    23         for(int i=1;i<=n;i++)
    24         {
    25             cin>>op>>s>>v;
    26 
    27             ///1操作
    28             if(op)
    29             {
    30                 ///存在则得出输入的字符串在数组中的下标k,查询下标为(k+v)的数组元素的值
    31                 if(mp.count(s))
    32                 {
    33                     list<Node> ::iterator it=mp[s];
    34                     if(v==-1)
    35                     {
    36                         if(it==l.begin())
    37                             cout<<"Invalid
    ";
    38                         else
    39                         {
    40                             it--;
    41                             cout<<it->v<<"
    ";
    42                         }
    43                     }
    44                     else if(v==0)
    45                         cout<<it->v<<"
    ";
    46                     else
    47                     {
    48                         it++;
    49                         if(it==l.end())
    50                             cout<<"Invalid"<<"
    ";
    51                         else
    52                             cout<<it->v<<"
    ";
    53                     }
    54                 }
    55                 ///若k或(k+v)不存在都输出Invalid。
    56                 else
    57                     cout<<"Invalid
    ";
    58             }
    59             ///0操作
    60             else
    61             {
    62                 ///存在则 把它取出来,原有值保持不变,压入数组末尾。
    63                 if(mp.count(s))
    64                 {
    65                     list<Node> ::iterator it=mp[s];
    66                     cout<<it->v<<"
    ";
    67                     l.push_back(Node{it->ss,it->v});
    68                     l.erase(it);
    69                     it=l.end();
    70                     it--;
    71                     mp[s]=it;
    72                 }
    73                 ///不存在则直接加入到末尾,值为输入的v。
    74                 else
    75                 {
    76                     cout<<v<<"
    ";
    77                     l.push_back(Node{s,v});
    78                     list<Node> ::iterator it=l.end();
    79                     it--;
    80                     mp[s]=it;
    81                 }
    82                 int sz=l.size();
    83                 while(sz>m)
    84                 {
    85                     mp.erase(l.begin()->ss);
    86                     l.pop_front();
    87                     sz--;
    88                 }
    89             }
    90         }
    91     }
    92 }
    View Code
  • 相关阅读:
    【剑指Offer面试编程题】题目1504:把数组排成最小的数--九度OJ
    【剑指Offer面试编程题】题目1373:整数中1出现的次数--九度OJ
    【剑指Offer面试编程题】题目1372:最大子向量和--九度OJ
    【剑指Offer面试编程题】题目1371:最小的K个数--九度OJ
    vue路由传参
    Es5.Es6区别
    面向对象和面向过程
    vuex
    Vue脚手架使用
    vue中fetch请求
  • 原文地址:https://www.cnblogs.com/MMMinoz/p/11251613.html
Copyright © 2011-2022 走看看