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\n",Ans.size());
57         for(auto x:Ans)printf("%d %d\n",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\n",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\n",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 {\binom{p}{i}*(k-4)^{p-i}*(\sqrt{x}+\frac{1}{\sqrt{x}})^{2i}}=\sum_{i=0}^p {\binom{p}{i}*(k-4)^{p-i}*\sum_{j=0}^{2i} {\binom{2i}{j}*x^{i-j}}}\)

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

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

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

\(\sum_{i=0}^p {\binom{p}{i}*(k-4)^{p-i}*\frac{2^{2i}-\binom{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",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

 

posted @ 2019-11-25 17:12  幽蝶  阅读(201)  评论(0编辑  收藏  举报