• codeforces #602 (div 1) 做题记录


    A.

    先利用一半次数来构造()()()()()()的结构(两个一组,找后面不同的第一个位置reverse)

    然后构造((()))()()() (对于每个右括号,找后面第一个左括号)

     1 #include<bits/stdc++.h>
     2 #define pii pair<int,int>
     3 #define mp(a,b) make_pair(a,b)
     4 #define maxn 2005
     5 using namespace std;
     6 int T,n,k; 
     7 char s[maxn];
     8 vector<pii> Ans;
     9 int main()
    10 {
    11     scanf("%d",&T);
    12     while(T--)
    13     {
    14         scanf("%d%d",&n,&k);
    15         scanf("%s",s+1);
    16         Ans.clear();
    17         for(int i=1;i<=n;++i)
    18         {
    19             if(s[i]=='(')
    20             {
    21                 int j=i+1;
    22                 bool yes=0;
    23                 for(;j<=n;++j)if(s[j]==')'){yes=1;break;}
    24                 if(yes)
    25                 {
    26                     Ans.push_back(mp(i+1,j));
    27                     reverse(s+i+1,s+j+1);
    28                 }
    29                 i++;
    30             }
    31             else
    32             {
    33                 int j=i+1;
    34                 bool yes=0;
    35                 for(;j<=n;++j)if(s[j]=='('){yes=1;break;}
    36                 if(yes)
    37                 {
    38                     Ans.push_back(mp(i,j));
    39                     reverse(s+i,s+j+1);
    40                 }
    41                 i++;
    42             }
    43         }
    44         int cnt=n/2;
    45         for(int i=1;i<=n;++i)if(s[i]==')')
    46         {
    47             if(cnt==k)break;
    48             for(int j=i+1;j<=n;++j)if(s[j]=='(')
    49             {
    50                 Ans.push_back(mp(i,j));
    51                 reverse(s+i,s+j+1);
    52                 cnt--;
    53                 break;
    54             }
    55         }
    56         printf("%d
    ",Ans.size());
    57         for(auto x:Ans)printf("%d %d
    ",x.first,x.second);
    58     }
    59 }
    View Code

    B.

    离线询问,然后贪心从大到小往里加

    每次选的位置是值最大情况下位置最小的

    然后这个可以线段树维护

    回答询问可以线段树上二分

     1 #include<bits/stdc++.h>
     2 #define maxn 200005
     3 using namespace std;
     4 int n,m;
     5 int a[maxn];
     6 int maxv[maxn<<2];
     7 vector< pair<int,int> > q[maxn];
     8 void pushup(int rt)
     9 {
    10     maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);
    11 }
    12 void build(int rt,int l,int r)
    13 {
    14     if(l==r){maxv[rt]=a[l];return;}
    15     int mid=(l+r)>>1;
    16     build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
    17     pushup(rt); 
    18 }
    19 int update(int rt,int l,int r)
    20 {
    21     if(l==r)
    22     {
    23         maxv[rt]=0;
    24         return l;
    25     }
    26     int mid=(l+r)>>1,ans=0;
    27     if(maxv[rt<<1]>=maxv[rt<<1|1])ans=update(rt<<1,l,mid);
    28     else ans=update(rt<<1|1,mid+1,r);
    29     pushup(rt);
    30     return ans;
    31 }
    32 int sz[maxn<<2];
    33 void add(int rt,int l,int r,int pos)
    34 {
    35     sz[rt]++;
    36     if(l==r)return;
    37     int mid=(l+r)>>1;
    38     if(pos<=mid)add(rt<<1,l,mid,pos);
    39     else add(rt<<1|1,mid+1,r,pos);
    40 }
    41 int query(int rt,int l,int r,int k)
    42 {
    43     if(l==r)return l;
    44     int mid=(l+r)>>1;
    45     if(k<=sz[rt<<1])return query(rt<<1,l,mid,k);
    46     else return query(rt<<1|1,mid+1,r,k-sz[rt<<1]);
    47 }
    48 int Ans[maxn];
    49 int main()
    50 {
    51     scanf("%d",&n);
    52     for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    53     scanf("%d",&m);
    54     for(int i=1;i<=m;++i)
    55     {
    56         int x,y;
    57         scanf("%d%d",&x,&y);
    58         q[x].push_back(make_pair(y,i));
    59     }
    60     build(1,1,n);
    61     for(int i=1;i<=n;++i)
    62     {
    63         int x=update(1,1,n);
    64         add(1,1,n,x);
    65         for(auto u:q[i])
    66         {
    67             int k=u.first,id=u.second;
    68             Ans[id]=a[query(1,1,n,k)];
    69         }
    70     }
    71     for(int i=1;i<=m;++i)printf("%d
    ",Ans[i]);
    72 }
    View Code

    C.

    二分答案(T)

    然后找出所有可能的起始点(周围((2T+1)*(2T+1))为'X')

    然后check是否可行

     1 #include<bits/stdc++.h>
     2 #define maxn 1000005
     3 using namespace std;
     4 int n,m;
     5 char str[maxn];
     6 vector<char> a[maxn];
     7 vector<int> c[maxn],sum[maxn];
     8 bool full(int x,int y,int k)
     9 {
    10     if(x-k<1||y-k<1||x+k>n||y+k>m)return 0;
    11     int sx=max(1,x-k),sy=max(1,y-k),tx=min(n,x+k),ty=min(m,y+k);
    12     return sum[tx][ty]-sum[tx][sy-1]-sum[sx-1][ty]+sum[sx-1][sy-1]==(tx-sx+1)*(ty-sy+1);
    13 }
    14 bool check(int k)
    15 {
    16     for(int i=0;i<=n+1;++i)
    17         for(int j=0;j<=m+1;++j)c[i][j]=0;
    18     for(int i=1;i<=n;++i)
    19         for(int j=1;j<=m;++j)
    20         {
    21             if(full(i,j,k))
    22             {
    23                 int sx=i-k,sy=j-k,tx=i+k,ty=j+k;
    24                 c[tx+1][ty+1]++;c[sx][ty+1]--;c[tx+1][sy]--;c[sx][sy]++;
    25             }
    26         }
    27     for(int i=1;i<=n;++i)
    28         for(int j=1;j<=m;++j)c[i][j]+=c[i][j-1];
    29     for(int j=1;j<=m;++j)
    30         for(int i=1;i<=n;++i)c[i][j]+=c[i-1][j];
    31     for(int i=1;i<=n;++i)
    32         for(int j=1;j<=m;++j)
    33         {
    34             if(c[i][j]&&a[i][j]=='.')return 0;
    35             if(!c[i][j]&&a[i][j]=='X')return 0;
    36         }
    37     return 1; 
    38 }
    39 int main()
    40 {
    41     scanf("%d%d",&n,&m);
    42     for(int i=0;i<=n+1;++i)a[i].resize(m+2),sum[i].resize(m+2),c[i].resize(m+2);
    43     for(int i=1;i<=n;++i)
    44     {
    45         scanf("%s",str+1);
    46         for(int j=1;j<=m;++j)a[i][j]=str[j]; 
    47     }
    48     for(int i=1;i<=n;++i)
    49         for(int j=1;j<=m;++j)sum[i][j]=(a[i][j]=='X');
    50     for(int i=1;i<=n;++i)
    51         for(int j=1;j<=m;++j)sum[i][j]+=sum[i][j-1];
    52     for(int j=1;j<=m;++j)
    53         for(int i=1;i<=n;++i)sum[i][j]+=sum[i-1][j];
    54     int l=0,r=max(n,m),ans=0;
    55     while(l<=r)
    56     {
    57         int mid=(l+r)>>1;
    58         if(check(mid))ans=mid,l=mid+1;
    59         else r=mid-1;
    60     }
    61     printf("%d
    ",ans);
    62     for(int i=1;i<=n;++i)
    63     {
    64         for(int j=1;j<=m;++j)printf("%c",full(i,j,ans)?'X':'.');
    65         puts("");
    66     }
    67 }
    View Code

     D.

    考虑一个暴力的方法:

    (dp[i][j])表示到第(i)个数,然后相对移位之前得分为(j)的方案数

    转移是:

      (a[i]==a[j])时(dp[i][j]=dp[i-1][j]*k)

      (a[i]!=a[j])时(dp[i][j]=dp[i-1][j]*(k-2)+dp[i-1][j-1]+dp[i-1][j+1])

    上面那种情况统计有多少个最后贡献乘一下就好了

    下面那种情况可以利用生成函数解决

    初始多项式为(f(x)=1)

    然后每次下面那种情况的转移相当于乘一个多项式(g(x)=(x+x^{-1}+(k-2)))

    于是问题就变成了求((x+x^{-1}+(k-2))^p)的正指数的系数和

    这个东西可以用二项式定理推式子:

    ((x+x^{-1}+k-2)^p=[(sqrt{x}+frac{1}{sqrt{x}})^2+k-4]^p=sum_{i=0}^p {inom{p}{i}*(k-4)^{p-i}*(sqrt{x}+frac{1}{sqrt{x}})^{2i}}=sum_{i=0}^p {inom{p}{i}*(k-4)^{p-i}*sum_{j=0}^{2i} {inom{2i}{j}*x^{i-j}}})

    取(exp>0)的系数和为:

    (sum_{i=0}^p {inom{p}{i}*(k-4)^{p-i}*sum_{j=0}^{i-1} {inom{2i}{j}}})

    利用二项式展开和组合数的对称性:

    (sum_{i=0}^p {inom{p}{i}*(k-4)^{p-i}*frac{2^{2i}-inom{2i}{i}}{2}})

    这东西可以(O(nlogn))求

    于是就做完了

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 #define maxn 400005
     4 using namespace std;
     5 const ll mod = 998244353;
     6 int n,a[maxn];
     7 ll k;
     8 ll fac[maxn],inv[maxn];
     9 ll fastpow(ll a,ll p)
    10 {
    11     ll ans=1;
    12     while(p)
    13     {
    14         if(p&1)ans=ans*a%mod;
    15         a=a*a%mod;p>>=1; 
    16     }
    17     return ans;
    18 }
    19 ll getpow(ll a,ll p)
    20 {
    21     return fastpow((a%mod+mod)%mod,p);
    22 }
    23 ll C(ll x,ll y)
    24 {
    25     return fac[x]*inv[x-y]%mod*inv[y]%mod;
    26 }
    27 int main()
    28 {
    29     fac[0]=1;inv[0]=1;
    30     for(int i=1;i<=400000;++i)fac[i]=fac[i-1]*i%mod;
    31     for(int i=1;i<=400000;++i)inv[i]=getpow(fac[i],mod-2);
    32     scanf("%d%I64d",&n,&k);
    33     for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    34     ll t=0,p=0;
    35     for(int i=2;i<=n;++i)if(a[i]==a[i-1])t++;else p++;
    36     if(a[n]==a[1])t++;else p++;
    37     ll ans=0;
    38     for(int i=1;i<=p;++i)
    39     {
    40         ll res=C(p,i)*getpow(k-4,p-i)%mod*(getpow(2,2*i)%mod-C(2*i,i)+mod)%mod*fastpow(2,mod-2)%mod;
    41         ans=(ans+res)%mod;
    42     }
    43     ans=ans*getpow(k,t)%mod;
    44     cout<<ans<<endl; 
    45 }
    View Code

     E.

    考虑按列错位构造:

    (本题为了方便起见,采用0-index描述)

    按降序排序,然后第(i)列起始位置为(i),向下延伸(a_i)个(模意义下)

    然后这么做的正确性可以这样证明:

    对于第(i)行,我们来证明它和第(i+1)行到第(n-1)行不同

    如果(a_{ij}=0)则(i,j)两行不同

    否则(a_{ij}=1),表明了第(j)列是延伸到最下方然后循环延伸过来的

    那么我们找一个(k,k<j),使得(a_{ik}=0)

    这时候由于长度是递减的连续段,那么有(a_{jk}=1),这样(i,j)两行不同

    然后来证明其他行和第(n)行不同:

    如果(a_{ni}=0),那么由于(a_{ii}=1),则(i,n)两行不同

    否则(a_{ni}=1),那么由于长度是递减的,一定可以找到前面一个位置使(a_{nk}=0,a{ik}=1)

     1 #include<bits/stdc++.h>
     2 #define maxn 1005
     3 using namespace std;
     4 int n;
     5 struct Data
     6 {
     7     int x,id;
     8 }a[maxn];
     9 bool operator < (Data A,Data B){return A.x>B.x;}
    10 int Ans[maxn][maxn];
    11 int main()
    12 {
    13     scanf("%d",&n);
    14     for(int i=1;i<=n;++i)scanf("%d",&a[i].x),a[i].id=i;
    15     sort(a+1,a+n+1);
    16     int st=0;
    17     for(int i=1;i<=n;++i)
    18     {
    19         int pos=a[i].id;
    20         for(int j=0;j<a[i].x;++j)Ans[(st+j)%(n+1)][pos]=1;
    21         st++;
    22     }
    23     printf("%d
    ",n+1); 
    24     for(int i=0;i<=n;++i)
    25     {
    26         for(int j=1;j<=n;++j)printf("%d",Ans[i][j]);
    27         puts("");
    28     }
    29 }
    View Code
  • 相关阅读:
    响应式开发
    web作业小结
    js的简单数据类型和复杂数据类型
    JavaScript 字符串对象
    JavaScript 数组篇
    JavaScript 对象篇
    spfa优化
    HZNU Training 28 for Zhejiang Provincial Competition 2020
    [kuangbin带你飞]专题十一 网络流
    HZNU Training 26 for Zhejiang Provincial Competition 2020
  • 原文地址:https://www.cnblogs.com/uuzlove/p/11929037.html
Copyright © 2020-2023  润新知