20191001

B组题果然是噩梦……

好歹是在一机房待过几天的人,然而B组题每考每炸。

第一场:

 第二场:

 

 第三场:

 

 (截屏技术实在不行请大佬见谅

前两场都各有将近10个200+我都稳定AC100分被kx疯狂dis;

最后一场题巨水AK神巨多而我才刚破百。

还是不要把题想得太复杂了吧。

 T1

贪心,傻逼已经不足以形容它。

直接按b-a从大到小排序,直接安排士兵即可。

时空复杂度$\Theta(N)$。

大约打了2分钟?

对拍全过了?

结果WA80。

经板B哥哥指点,我把

 改成

 AC……

因为对拍的暴力只是把sort完的固定顺序改成next_permutation暴枚所有顺序,这句话打的一模一样,所以自然拍不出来。

以后要注意一下子分析全各种情况,还有除了对拍还要稍手摸几组样例了这个。

出题人实在太善良没取max还给80

还有不sort的多测不清空的都能拿80%%%出题人

#include
#include
using namespace std;
inline int read(){
    int ss(0);char bb(getchar());
    while(bb<48||bb>57)bb=getchar();
    while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
    return ss;
}
struct node{
    int a,b;
}q[100001];
inline int _max(int x,int y){
    return x>y?x:y;
}
int main(){
    int T=read();
    while(T--){
        int n=read();
        long long ans(0);
        for(register int i=1;i<=n;++i)q[i].a=read(),q[i].b=read();
        sort(q+1,q+n+1,[](node skyh,node yxs){
            return skyh.b-skyh.a>yxs.b-yxs.a;
        });
        for(register int i(1),now(0);i<=n;++i)
            ans+=_max(q[i].b-now,0),now=_max(q[i].b,now)-q[i].a;
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

T2

应该是本场考试唯一有些难度的题。

有些思维含量,于是乎我就想不出来了

考场上一直在想二项式反演,我怕是脑抽了……

这个题放在文化课里其实也是一个很棒的题。

考虑把${C_n^i}^2$转换成$C_n^i\times C_n^{n-i}$。

相当于有2n个物品,先在前n个物品选i个,后n个物品选n-i个。

由于$i\in[0,n]$,所以方案数之和等价于在直接在2n个物品里选n个的方案数。

预处理阶乘和逆元,对于每个询问输出$C_{2n}^n$即可。

时间复杂度$\Theta(N+T)$。

空间复杂度$\Theta(N)$,注意数组开到数据范围的2倍,阶乘逆元也要递推到数据范围的2倍。

还挺不错的,可惜只能给我这种眼浊的人做,不然一打表就看出来了。

#include
#define ll long long
using namespace std;
int const N=2e6+1,mod=1e9+7;
int n;
ll fac[N],inv[N];
inline int read(){
    int ss(0);char bb=getchar();
    while(bb<48||bb>57)bb=getchar();
    while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
    return ss;
}
inline ll power(ll x,int y){
    ll ans(1);
    for(;y;y>>=1,x=x*x%mod)
        if(y&1)ans=ans*x%mod;
    return ans;
}
inline ll C(int x,int y){
    return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
int main(){
    fac[0]=fac[1]=1;
    for(register int i=2;i1]*i%mod;
    inv[N-1]=power(fac[N-1],mod-2);
    for(register int i=N-1;i;--i)inv[i-1]=inv[i]*i%mod;
    int T=read();
    while(T--)
        n=read(),printf("%lld\n",C(n<<1,n));
    return 0;
}
View Code

T3

以前做过一道类似的题,Hash二分给我的印象很深刻,所以我上来就打……

通过Hash二分和差分可以在$\Theta(NlogN)$的时间内可以求出$[1,r],r\in[1,n]$区间内的回文串个数,设为w[r](还可以求出以r为结尾的回文串数量ed[r])。

一开始我想的很简单,对于询问(l,r)直接w[r]-w[l-1]。

但如果设左端点是le,右端点是re的话,这样会多出$le\in[1,l),re\in[l,r]$的情况。

所以我又用$\Theta(N^2)$的时间处理出区间[1,r]中经过l的回文串数量ps[l][r]。

那么对于询问(l,r)答案就是w[r]-w[l-1]-ps[l-1][r]+ed[l-1]

时空复杂度$\Theta(N^2)$。

然而因为需要$\Theta(N^2)$处理出ps数组,所以二分Hash失去意义,还不如直接区间DP出答案……

直接套树状数组$\Theta(N^2logN)$也能过而且代码巨短还比正解快。

反正我的做法肯定是最SB的了,不过幸好还是AC了。

#include
#define ull unsigned long long
#define ll long long
using namespace std;
int const N=5005;
ull const p=23333;
ull b[N],h1[N],h2[N];
int n;
int cf[N],w[N],ed[N];
int ps[N][N];
char s[N];
inline int read(){
    int ss(0);char bb=getchar();
    while(bb<48||bb>57)bb=getchar();
    while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
    return ss;
}
inline int min(int x,int y){
    return xx:y;
}
inline ull cal1(int l,int r){
    return h1[r]-h1[l]*b[r-l];
}
inline ull cal2(int l,int r){
    return h2[r]-h2[l]*b[l-r];
}
int main(){
    b[0]=1;
    register char bb=getchar();
    while(bb<'a'||bb>'z')bb=getchar();
    for(;bb>='a'&&bb<='z';bb=getchar())
        s[++n]=bb,b[n]=b[n-1]*p,h1[n]=h1[n-1]*p+bb;
    for(register int i=n;i;--i)
        h2[i]=h2[i+1]*p+s[i];
    for(register int i=1;i<=n;++i){
        int l=0,r=min(i-1,n-i);
        while(l<r){
            int mid=l+r+1>>1;
            if(cal1(i-mid-1,i+mid)==cal2(i+mid+1,i-mid))l=mid;
            else r=mid-1;
        }
        ++cf[i],--cf[i+l+1];
        for(register int j=i-l;j1)-j],--ps[j][i+l+1];
        for(register int j=i;j<=i+l;++j)++ps[j][j],--ps[j][i+l+1];
        if(i==n||s[i]!=s[i+1])continue;
        l=0,r=min(i-1,n-i-1);
        while(l<r){
            int mid=l+r+1>>1;
            if(cal1(i-mid-1,i+mid+1)==cal2(i+mid+2,i-mid))l=mid;
            else r=mid-1;
        }
        ++cf[i+1],--cf[i+l+2];
        for(register int j=i-l;j<=i;++j)++ps[j][(i<<1)-j+1],--ps[j][i+l+2];
        for(register int j=i+l+1;j>i;--j)++ps[j][j],--ps[j][i+l+2];
    }
    for(register int i=1,ct=0;i<=n;++i)
        ct+=cf[i],w[i]=w[i-1]+(ed[i]=ct);
    for(register int i=1;i<=n;++i)
        for(register int j=1,ct=0;j<=n;++j)
            ct+=ps[i][j],ps[i][j]=ps[i][j-1]+ct;
    int T=read();
    while(T--){
        int l=read(),r=read();
        if(l>r){puts("0");continue;}
        //printf("%d %d %d %d\n",w[r],w[l-1],ps[l-1][r],ed[l-1]);
        printf("%d\n",w[r]-w[l-1]-ps[l-1][r]+ed[l-1]);
    }
    return 0;
}
View Code

你可能感兴趣的:(20191001)