2019杭电多校第二场

1010 Just Skip The Problem

一次询问 n n n个串,第 i i i个串第 i i i个位置为0,其余均为1
答案就是 m i n ( n ! , m o d ) min(n!,mod) min(n!,mod)
不过出题人似乎并没有考虑 1 1 1的时候答案是 2 2 2(询问 1 1 1 0 0 0都可以)

#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
long long mod,x,i,res[1000005];
int main()
{
    mod = 1000003;
    res[0] = 1;
    fo(i,1,mod) res[i] = (res[i-1] * i) % mod;
    while (~scanf("%d",&x))
    {
        if (x == 1) cout<<2<<endl; else
        if (x >= mod) cout<<0<<endl; else
        {
            cout<<res[x]<<endl;
        }
    }
    return 0;
}

1011 Keen On Everything But Triangle

区间查询前 44 44 44大的数,每次找最大两个数判断
std给出了 n l o g 2 n ∗ 44 nlog_2n*44 nlog2n44的做法
我用线段树暴力维护区间最大值,T了。。。。。
最后是主席树一次性整体查询 K K K大值

#include
#define N 100000
using namespace std;
int a[N],b[N],root[N*20],ls[N*20],rs[N*20],sum[N*20];
int res[N];
int n,q,i,tot,k,ql,qr,qk;
void build(int l,int r,int &rt)
{
    rt = ++tot;
    sum[rt] = 0; if (l == r) return;
    int m = (l + r) >> 1;
    build(l,m,ls[rt]); 
    build(m+1,r,rs[rt]);
}
void update(int l,int r,int &rt,int last,int p)
{
    rt = ++tot;
    ls[rt] = ls[last]; rs[rt] = rs[last];
    sum[rt] = sum[last] + 1;
    if (l == r) return;
    int m = (l + r) >> 1;
    if (p <= m) update(l,m,ls[rt],ls[last],p);
        else    update(m+1,r,rs[rt],rs[last],p);
}
void query(int ss,int tt,int l,int r,int kl,int kr)
{
    if (l == r) {for (int i = kl;i <= kr; i++) res[i] = -b[l]; return;}
    int m = (l + r) >> 1;
    int cnt = sum[ls[tt]] - sum[ls[ss]];
    if (kr - kl + 1 <= cnt)
        query(ls[ss],ls[tt],l,m,kl,kr); 
    else
        {
            query(ls[ss],ls[tt],l,m,kl,kl+cnt-1);
            query(rs[ss],rs[tt],m+1,r,kl+cnt,kr);
        }
}
int main()
{
    while (~scanf("%d%d",&n,&q))
    {
        for (i = 1;i <= n; i++) scanf("%d",&a[i]);
        for (i = 1;i <= n; i++) a[i] = -a[i];
        
        for (i = 1;i <= n; i++) b[i] = a[i];
        sort(b+1,b+n+1);
        k = unique(b+1,b+n+1) - (b+1);
        for (i = 1;i <= n; i++) a[i] = lower_bound(b+1,b+k+1,a[i])-b;
        
        tot = 0;
        build(1,k,root[0]);
        for (i = 1;i <= n; i++) update(1,k,root[i],root[i-1],a[i]);
        
        while (q--)
            {
                scanf("%d%d",&ql,&qr);
                qk = min(qr-ql+1,45);
                
                query(root[ql-1],root[qr],1,k,1,qk);
                long long ans = -1;
                for(i = 3;i <= qk; i++)
                {
                    if (res[i-2] - res[i-1] < res[i])
                    {
                        ans = 1ll*res[i-2] + res[i-1] + res[i];
                        printf("%I64d\n",ans);
                        break;
                    }
                }
                if (ans == -1) printf("-1\n");
            }
    }
    return 0;
}

1012 Longest Subarray

场上想了一个巨麻烦的做法
首先合法情况下每个数至少出现 K K K次,那么如果有某个数出现小于 K K K次,那么将这个序列分成 K + 1 K+1 K+1段进行递归
不过这样做没有优化就会被卡掉。。。
比如: 55454343232121 55454343232121 55454343232121
每次只会去掉最后三个数,然后就会退化成 N 2 N^2 N2
可以用启发式合并,也就是说每次只做较短的区间,然后用总区间减去小区间得到大区间
不过 s t d std std的做法更巧妙
固定右端点,对于每种元素,他的合法区间一定是两段连续区间:

你可能感兴趣的:(杭电多校)