zoukankan      html  css  js  c++  java
  • HDU校赛 | 2019 Multi-University Training Contest 6

    2019 Multi-University Training Contest 6

    http://acm.hdu.edu.cn/contests/contest_show.php?cid=853

    1002. Nonsense Time

    这题比较神奇...有一个结论是:一个长度为(n)的随机排列的最长上升子序列期望长度为(O(sqrt n))

    那么我们考虑倒着删数,每次暴力处理出当前任意一个最长上升子序列,然后删除(x)的时候判一下(x)在不在当前的序列中,在就重新求一遍,否则不管。

    由于数据随机,(x)在序列中的概率是(frac{1}{sqrt n}),所以期望暴力求(sqrt n)( m LIS),所以复杂度是(O(nsqrt nlog n))

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    
    const int maxn = 1e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
    
    int p[maxn],k[maxn],vis[maxn],n,in[maxn],ans[maxn],len,f[maxn];
    
    struct tree_array {
        int t[maxn];
        void clear() {for(int i=1;i<=n;i++) t[i]=0;}
        void modify(int x,int v) {for(;x<=n;x+=x&-x) t[x]=max(t[x],v);}
        int query(int x,int ans=0) {for(;x;x-=x&-x) ans=max(ans,t[x]);return ans;}
    }T;
    
    void get_lis() {
        T.clear();len=0;
        for(int i=1;i<=n;i++) {
            in[i]=0;if(vis[i]) continue;
            f[i]=T.query(p[i]-1)+1;
            T.modify(p[i],f[i]);len=max(len,f[i]);
        }int x=len,pre=1e9;
        for(int i=n;i;i--)
            if(f[i]==x&&p[i]<pre&&!vis[i]) x--,pre=p[i],in[i]=1;
        // puts("OK");
        // for(int i=1;i<=n;i++) printf("%d ",vis[i]);puts("");
        // for(int i=1;i<=n;i++) printf("%d ",in[i]);puts("");
    }
    
    void solve() {
        read(n);
        for(int i=1;i<=n;i++) read(p[i]);
        for(int i=1;i<=n;i++) read(k[i]);
        get_lis();ans[n+1]=len;
        for(int i=n;i;i--) {
            vis[k[i]]=1;
            if(in[k[i]]) get_lis();
            ans[i]=len;
        }for(int i=2;i<=n+1;i++) printf("%d%c",ans[i],i==n+1?'
    ':' ');
    }
    
    void clear() {
        for(int i=1;i<=n;i++) vis[i]=0;
    }
    
    int main() {
        int t;read(t);while(t--) solve(),clear();
        return 0;
    }
    

    1005. Snowy Smile

    这题挺无聊的,直接枚举左边界,拿一个右边界往后扫,遇到点就丢到线段树里,然后维护连续一段的和的最大值就好了。

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    #define ll long long 
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    
    const int maxn = 4e3+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
    
    struct data {int x,y,w;}a[maxn];
    int n,r[maxn],lx,ly;
    
    void init() {
        read(n);
        for(int i=1;i<=n;i++) read(a[i].x),read(a[i].y),read(a[i].w);
        for(int i=1;i<=n;i++) r[i]=a[i].x;
        sort(r+1,r+n+1),lx=unique(r+1,r+n+1)-r-1;
        for(int i=1;i<=n;i++) a[i].x=lower_bound(r+1,r+lx+1,a[i].x)-r;
        for(int i=1;i<=n;i++) r[i]=a[i].y;
        sort(r+1,r+n+1),ly=unique(r+1,r+n+1)-r-1;
        for(int i=1;i<=n;i++) a[i].y=lower_bound(r+1,r+ly+1,a[i].y)-r;
    }
    
    int cmp(data a,data b) {return a.x<b.x||(a.x==b.x&&a.y<b.y);}
    
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
    
    struct segment_tree {
        ll mx[maxn<<2],mxl[maxn<<2],mxr[maxn<<2],sum[maxn<<2];
    
        void update(int p) {
            mx[p]=max(mx[ls],mx[rs]);
            mx[p]=max(mx[p],max(mxl[rs]+sum[ls],mxr[ls]+sum[rs]));
            mx[p]=max(mx[p],mxl[rs]+mxr[ls]);
            mxl[p]=max(mxl[ls],sum[ls]+mxl[rs]);
            mxr[p]=max(mxr[rs],sum[rs]+mxr[ls]);
            sum[p]=sum[ls]+sum[rs];
        }
        
        void modify(int p,int l,int r,int x,int v) {
            if(l==r) return sum[p]+=v,mxl[p]=mxr[p]=mx[p]=max(0ll,sum[p]),void();
            if(x<=mid) modify(ls,l,mid,x,v);
            else modify(rs,mid+1,r,x,v);
            update(p);
        }
    
        void clear(int p,int l,int r) {
            mx[p]=mxl[p]=mxr[p]=sum[p]=0;
            if(l==r) return ;
            clear(ls,l,mid);clear(rs,mid+1,r);
        }
    }T;
    
    void solve() {
        init();sort(a+1,a+n+1,cmp);int pps=1;ll ans=0;
        for(int i=1;i<=lx;i++) {
            T.clear(1,1,ly);while(a[pps].x!=i) pps++;
            int p=pps;
            for(int j=i;j<=lx;j++) {
                while(a[p].x==j) T.modify(1,1,ly,a[p].y,a[p].w),p++;
                ans=max(ans,T.mx[1]);
            }
        }printf("%lld
    ",ans);
        for(int i=1;i<=n;i++) a[i].x=a[i].y=a[i].w=0;
    }
    
    int main() {
        int t;read(t);while(t--) solve();
        return 0;
    }
    

    1006. Far away

    这题挺有意思的,首先我们用这(n)个点把平面分割成(n^2)个块,那么在每个块中绝对值就不会变了。

    注意到({ m lcm}(2,3,4,5)=60),对于每个块枚举答案横纵坐标除(60)的余数,然后(O(n))判断合不合法,(O(1))统计答案就好了。

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    #define ll long long 
    
    const int maxn = 1e2+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
    
    struct data {int x,y,k,t;}a[maxn];
    int lx[maxn],ly[maxn],n,m;
    ll ans;
    
    int calc(int l,int r) {return l>=r?0:(r-l-1)/60+1;}
    
    int check(int x,int y) {
        for(int i=1;i<=n;i++) if((abs(x-a[i].x)+abs(y-a[i].y))%a[i].k!=a[i].t) return 0;
        return 1;
    }
    
    void solve() {
        read(n),read(m);ans=0;
        for(int i=1;i<=n;i++)
            read(a[i].x),lx[i]=a[i].x,read(a[i].y),ly[i]=a[i].y,read(a[i].k),read(a[i].t);
        sort(lx+1,lx+n+1);
        sort(ly+1,ly+n+1);
        ly[n+1]=m+1,lx[n+1]=m+1;
        for(int i=0;i<=n;i++) {
            if(lx[i+1]-lx[i]<=0) continue;
            for(int j=0;j<=n;j++) {
                if(ly[j+1]-ly[j]<=0) continue;
                for(int a=0;a<60;a++)
                    for(int b=0;b<60;b++) 
                        if(check(lx[i]+a,ly[j]+b)) 
                            ans+=1ll*calc(lx[i]+a,lx[i+1])*calc(ly[j]+b,ly[j+1]);
            }
        }printf("%lld
    ",ans);
    }
    
    void clear() {
        
    }
    
    int main() {
        int t;read(t);while(t--) solve(),clear();
        return 0;
    }
    

    1008. TDL

    注意到(m)很小,而(f(n,m)-n)相当于说第(m)小的与(n)互质的数,考虑到极端情况,取前(m+log n)个质数也一定能取到。

    所以直接暴力枚举(f(n,m)-n)的答案是多少,然后可以算出(n),得到(n)之后再检查一下(f(n,m)-n)是不是枚举的那么多。

    然后对于所有(n)取个最小值就好了。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    
    const int maxn = 1e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
    
    int m,k;
    
    void solve() {
        read(k),read(m);int res=2e18;
        for(int a=m;a<=1000;a++) {
            int n=k^a,ans=0,cnt=0;
            for(int i=1;i<=1000;i++) {
                if(__gcd(i,n)==1) cnt++;
                if(cnt==m) {ans=i;break;}
            }if(a==ans) res=min(n,res);
        }if(res>1e18) puts("-1");else write(res);
    }
    
    signed main() {
        int t;read(t);while(t--) solve();
        return 0;
    }
    

    1010. Ridiculous Netizens

    标算好像是玄学的树分治,但是我写了个暴力跑的比标算快(10​)倍....

    (那就这样算了)

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    #define iter map<int,int > :: iterator
    #define for_map(i,x) for(iter i=x.begin();i!=x.end();i++) 
    
    const int maxn = 3e3+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
    
    int n,m,head[maxn],tot,w[maxn],ans;
    struct edge{int to,nxt;}e[maxn<<1];
    
    void ins(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    
    map<int,int > f[maxn],now[2];
    
    void add(int &x,int y) {x+=y;if(x>=mod) x-=mod;}
    
    void dfs(int x,int fa) {
        for(int i=head[x];i;i=e[i].nxt)
            if(e[i].to!=fa) dfs(e[i].to,x);
        int t=0;now[t][w[x]]=1;
        for(int E=head[x];E;E=e[E].nxt) {
            int v=e[E].to;if(v==fa) continue;
            for_map(i,now[t]) {
                for_map(j,f[v]) 
                    if(1ll*i->fr*j->fr<=m) {
                        int r=i->fr*j->fr;
                        add(now[t^1][r],1ll*i->sc*j->sc%mod);
                    } else break;
                add(now[t^1][i->fr],i->sc);
            }
            now[t].clear();t^=1;
        }f[x]=now[t];now[t].clear();
        for_map(i,f[x]) add(ans,i->sc);
        for(int i=head[x];i;i=e[i].nxt) f[e[i].to].clear();
    }
    
    void solve() {
        read(n),read(m);ans=0;
        for(int i=1;i<=n;i++) read(w[i]);
        for(int i=1,x,y;i<n;i++) read(x),read(y),ins(x,y),ins(y,x);
        dfs(1,0);f[1].clear();write(ans);
        for(int i=1;i<=n;i++) head[i]=0;tot=0;
    }
    
    int main() {
        int t;read(t);while(t--) solve();
        return 0;
    }
    

    1012. Stay Real

    全场最水的题,因为是小根堆,每次选最大的就好了。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    
    const int maxn = 1e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
    
    int n,t[maxn],vis[maxn];
    
    priority_queue<pair<int,int > > q;
    
    void solve() {
        read(n);
        for(int i=1;i<=n;i++) vis[i/2]=1,read(t[i]);
        for(int i=1;i<=n;i++) if(!vis[i]) q.push(mp(t[i],i));
        int a=0,b=0;
        for(int i=1;i<=n;i++) {
            int x=q.top().second;q.pop();
            if(x/2&&vis[x/2]) q.push(mp(t[x/2],x/2)),vis[x/2]=0;
            if(i&1) a+=t[x];else b+=t[x];
        }printf("%lld %lld
    ",a,b);
    }
    
    void clear() {
        for(int i=1;i<=n;i++) vis[i]=0;
    }
    
    signed main() {
        int T;read(T);while(T--) solve(),clear();
        return 0;
    }
    
  • 相关阅读:
    点击有惊喜
    模态框案例
    DOM操作
    定时器
    函数和object
    shell 判断文件出现次数
    shell 判断路径
    shell 循环数组
    shell 判断为空打印
    shell 示例1 从1叠加到100
  • 原文地址:https://www.cnblogs.com/hbyer/p/11325410.html
Copyright © 2011-2022 走看看