D1
普及组。。。
T1/T2 咕
T3
链接:C
小A有一个只包含左右括号的字符串S。但他觉得这个字符串不够美观,因为它不是一个合法的括号串。一个合法的括号串是这样定义的:
()是合法的括号串
若A是合法的括号串,则(A)则是合法的括号串
若A,B是合法的括号串,则AB也是合法的括号串。
小A现在希望删掉S中若干个字符,使得剩下的字符串是一个合法的括号串。小A想知道有多少不同的方案。两个方案是不同的,当且仅当他们删除的位置不同。比如当S是(()时,有两种方案。分别是删掉第一个位置,或是删掉第二个位置。
dp,\(f[i][j]\)表示前\(i\)个位置未配平的左括号的个数为\(j\)的方案数,转移
\[f[i][j]=\left\{\begin{matrix} &s[i]='('\ \ | f[i][j]=f[i-1][j-1]+f[i-1][j]& \\ &s[i]='\ )'\ \ | f[i][j]=f[i-1][j]+f[i-1][j+1] & \end{matrix}\right.\]
标程是滚动数组,然鹅并不需要啊并不需要,直接压成一位数组即可,每次转移时左移或右移一位。
#include<iostream>
#include<cstdio>
using namespace std;
int i,m,n,j,k,a[1001][1001],b[10001],f[10001];
char c;
int main()
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
cin>>c;
if(c==')') b[i]=1;
}
f[0]=1;
for(i=1;i<=n;i++)
if(b[i]) for(j=1;j<=k;j++) f[j-1]+=f[j];
else {
k+=1;
for(j=k;j>=0;j--) f[j+1]+=f[j];
}
printf("%d",f[0]-1);
}
T4
链接:D
小A有n个长度都是L的字符串。这些字符串只包含前8个小写字符,'a'~'h'。但这些字符串非常的混乱,它们几乎长得互不相同。小A想通过一些规则,让它们长得尽可能相同。小A现在有K次机会,他可以每次机会,可以选择一对字符x,y,让x,y变成等价的字符(注意这里x,y和字符'x', 'y'不是一样的,只是个代号)。注意,等价关系是有传递性的。比如小A让'a'和'b'等价, 'b'和'c'等价,那么'a'和'c'等价。
对于两个长度字符串P,Q是等价的,当且仅当对于每一位,P的字符和Q的字符都是等价的。
小A希望你告诉他,要怎么利用好这K次机会(当然可以不用完),使得尽可能多对字符串是等价的。注意每对字符串只能算一次。
普及组考斯特林数...我可能真的只适合去玩泥巴
当k大于7时我们可以把图连成一棵树也就是全部匹配。
穷举匹配情况时间爆炸,所以枚举的是联通情况是为(8,8-K),在可以接受的范围内。
由于字符串长度很大,check答案还是会超时,所以Hash掉每个字母的出现情况一起判断即可
D2
T1
链接:A
小N得到了一个非常神奇的序列A。这个序列长度为N,下标从1开始。A的一个子区间对应一个序列,可以由数对[l,r]表示,代表A[l], A[l + 1], ..., A[r]这段数。对于一个序列B[1], B[2], ..., B[k],定义B的中位数如下:
先对B排序。得到新的序列C。
假如k是奇数,那么中位数为。假如k为偶数,中位数为。
对于A的所有的子区间,小N可以知道它们对应的中位数。现在小N想知道,所有长度>=Len的子区间中,中位数最大可以是多少。
一开始打算打60分的平衡树偏分来着...突然想到似乎可以二分?
由于中位数大小其实并不具有单调性(比如最小数在k>1的情况下无论如何也不会是中位数..)但是可行性还是单调的,每次check一个二分到的值\(x\)时把所有大于等于\(x\)的数全部赋值为1,小于\(x\)的数全部赋值为\(-1\)维护一个前缀和然后穷举每一个区间右端点然后找到长度大于等于k的最小值左端点,若相减只差大于0则最终答案肯定在\(x\)或\(x\)以上,否则则在\(x\)以下。
考试时写的愚蠢代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define update(now) c[now]=min(c[now*2],c[now*2+1])
using namespace std;
int i,m,j,k,a[100001],t[100001],pre[100001],maxx,c[500001],d[100001],e[100001],n,g[100001],w[100001];
void built(int now,int l,int r)
{
if(l==r) {c[now]=e[l]; return ;}
int mid=(l+r)>>1;
built(now*2,l,mid);
built(now*2+1,mid+1,r);
update(now);
}
int cha(int now,int l,int r,int rr)
{
int ans=0x3f3f3f3f;
if(r<=rr) return c[now];
int mid=(l+r)/2;
if(mid+1<=rr) ans=min(ans,cha(now*2+1,mid+1,r,rr));
ans=min(ans,cha(now*2,l,mid,rr));
return ans;
}
bool pan(int x)
{
memset(c,0x3f,sizeof(c));
memset(g,0,sizeof(g));
memset(w,0,sizeof(w));
e[0]=0;
for(int i=1;i<=n;i++)
{
if(a[i]>x) d[i]=1,g[i]=g[i-1];
else if(a[i]==x) d[i]=0, g[i]=i;
else d[i]=-1,g[i]=g[i-1];
e[i]=e[i-1]+d[i];
}
built(1,0,n);
for(int i=k;i<=n;i++)
if(e[i]-cha(1,0,n,i-k+1)>0) return 1;
for(int i=k;i<=n;i++)
if(g[i]) if(e[i]-cha(1,0,n,min(i-k,g[i]))>=0) return 1;
return 0;
}
int ef(int l,int r)
{
while(l<r)
{
int mid=(l+r+1)/2;
if(mid==36)
{
mid=36;
}
if(pan(mid)) l=mid;
else r=mid-1;
}
return l;
}
int main()
{
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++) scanf("%d",&a[i]),t[i]=a[i];
sort(t+1,t+n+1);
m=unique(t+1,t+1+n)-t-1;
for(int i=1;i<=n;i++)
{
int z=lower_bound(t+1,t+1+m,a[i])-t;
pre[z]=a[i]; a[i]=z;
maxx=max(maxx,a[i]);
}
printf("%d",pre[ef(1,maxx)]);
}
然鹅并不用啊,最小值是单调的....
修改后
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int i,m,j,k,a[100001],maxx,c[500001],d[100001],e[100001],n,tmp;
bool pan(int x)
{
for(int i=1;i<=n;i++)
{
if(a[i]>=x) e[i]=e[i-1]+1;
else e[i]=e[i-1]-1;
}
int p=0x3f3f3f3f;
for(int i=k;i<=n;i++)
{
p=min(p,e[i-k]);
if(e[i]-p>0) return 1;
}
return 0;
}
int main()
{
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++) scanf("%d",&a[i]),maxx=max(maxx,a[i]);
int l=1, r=maxx;
while(l<=r)
{
int mid=(l+r)/2;
if(pan(mid)) tmp=mid,l=mid+1;
else r=mid-1;
}
printf("%d",tmp);
}
T2
链接:B
小N对于数字的大小一直都有两种看法。第一种看法是,使用字典序的大小(也就是我们常用的判断数字大小的方法,假如比较的数字长度不同,则在较短一个前面补齐前导0,再比较字典序),比如43<355,10<11。第二种看法是,对于一个数字,定义他的权值为,也就是各个数位的乘积。
现在给定两个区间,[L,R]与[L1,R1]。小N现在想知道,有多少使用字典序判大小法在[L,R]之间的数字,满足其第二种定义的权值也在[L1,R1]之间。
换句话说,对于一个数x,定义f(x)为x的各个数位的乘积。对于L<=x<=R,问有多少x满足,L1<=f(x)<=R1。
恶意拉长题目描述差评
45分暴力很好啊QWQ
正解
数位dp,把情况分为两种,包含0和不包含0,然后包含0为至少含有1个0的情况,特判即可。
不包含0
把\(L1,R1\)质因数分解,由于每一位都\(\in[x|9\leq x\leq1]\)所以分解出的质因数也只有\(2,3,5,7\)四个且都不会超过60个。然后就是数位dp
T3
链接:https://www.nowcoder.com/acm/contest/164/C
来源:牛客网
小A有一个只包含左右括号的字符串S。但他觉得这个字符串不够美观,因为它不是一个合法的括号串。一个合法的括号串是这样定义的:
()是合法的括号串
若A是合法的括号串,则(A)则是合法的括号串
若A,B是合法的括号串,则AB也是合法的括号串。
小A现在希望删掉S中若干个字符,使得剩下的字符串是一个合法的括号串。小A想知道有多少不同的方案。两个方案是不同的,当且仅当他们删除的位置不同。比如当S是(()时,有两种方案。分别是删掉第一个位置,或是删掉第二个位置。
一看就是万恶的数据结构题...(咕咕咕