HDU校赛 | 2019 Multi-University Training Contest 3

2019 Multi-University Training Contest 3

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

1004. Distribution of books

考虑二分答案,设当前二分出来的是\(x\)。

设\(f_i\)表示前\(i\)个能分成最多的段数,使得每一段和都\(\leqslant x\)。

转移显然,枚举一个\(j\),若\(s_i-s_j\leqslant x\)则转移,\(s_i\)表示前缀和。

式子变一下就是\(s_i\leqslant x+s_j\),那么对于每个\(f_i\)把值扔到\(x+s_j\)这个位置,随便拿个什么维护一下,每次查询就好了,复杂度\(O(Tn\log ^2n)\)。

#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('\n');}

#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 = 4e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7;

int n,a[maxn],f[maxn],s[maxn],k;

#define ls p<<1
#define rs p<<1|1

struct Segment_Tree {
    int t[maxn*8];
    void modify(int p,int l,int r,int x,int v) {
        t[p]=max(t[p],v);
        if(l==r) return ;int mid=(l+r)>>1;
        if(x<=mid) modify(ls,l,mid,x,v);
        else modify(rs,mid+1,r,x,v);
    }

    int query(int p,int l,int r,int x,int y) {
        if(x<=l&&r<=y) return t[p];
        int mid=(l+r)>>1,ans=0;
        if(x<=mid) ans=max(ans,query(ls,l,mid,x,y));
        if(y>mid) ans=max(ans,query(rs,mid+1,r,x,y));
        return ans;
    }

    void build(int p,int l,int r) {
        t[p]=0;if(l==r) return ;int mid=(l+r)>>1;
        build(ls,l,mid),build(rs,mid+1,r);
    }
}T;

int r[maxn],tot;

int check(int x) {
    tot=0;
    FOR(i,1,n) f[i]=0,r[++tot]=s[i],r[++tot]=s[i]+x;
    sort(r+1,r+tot+1);int m=unique(r+1,r+tot)-r-1;
    T.build(1,1,m);
    for(int i=1;i<=n;i++) {
        int pps=lower_bound(r+1,r+m+1,s[i])-r;
        int ppsw=lower_bound(r+1,r+m+1,s[i]+x)-r;
        int a=T.query(1,1,m,pps,m);
        if(!a) f[i]=s[i]<=x?1:0;
        else f[i]=a+1;
        if(f[i]>=k) return 1;
        T.modify(1,1,m,ppsw,f[i]);
    }return 0;
}

void solve() {
    read(n),read(k);
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    int l=-2e14,r=1e9,ans=r;
    while(l<=r) {
        int mid=(l+r)>>1;
        if(check(mid)) r=mid-1,ans=mid;
        else l=mid+1;
    }write(ans);
}

signed main() {
    int t;read(t);while(t--) solve();
    return 0;
}

1006. Fansblog

挺无聊的题。。。考你会不会素数密度和威尔逊定理(这个名字也是我看了题解才知道的)。。

反正就是说对于一个素数\(p\),必然满足\((p-2)!\equiv 1\pmod p\)。

那么直接暴力就好了,我随便蒯了个我以前的\(\rm Miller\_robon\)的板子。

#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('\n');}

#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;

const int pri[] = {0,2,3,5,7,11,13,23,31};

int gcd(int a,int b) {return !b?a:gcd(b,a%b);}

int mul(int x,int y,int p) {
    int t=(long double)x*y/p;
    int res=x*y-t*p;res%=p;if(res<0) res+=p;
    return res;
}

int qpow(int a,int x,int p) {
    int res=1;
    for(;x;x>>=1,a=mul(a,a,p)) if(x&1) res=mul(res,a,p);
    return res;
}

bool MR(int n) {
    if(n<2) return 1;
    int e=(n-1)>>__builtin_ctz(n-1);
    for(int i=1;i<=8;i++) {
        if(pri[i]>=n) break;
        for(int d=e,lst=qpow(pri[i],d,n),now;d!=n-1;d<<=1,lst=now) {
            now=mul(lst,lst,n);
            if(lst!=1&&lst!=n-1&&now==1) return 0;
        }if(qpow(pri[i],n-1,n)!=1) return 0;
    }return 1;
}

int p,q;

void solve() {
    read(p);int ans=p-1;
    for(int i=p-1;;i--) {
        if(MR(i)) {break;}
        ans=mul(ans,qpow(i,p-2,p),p);
    }
    write(ans);
}

signed main() {
    int t;read(t);while(t--) solve();
    return 0;
}

1011. Squrirrel

显然可以发现根定在直径上比较优。

那么直接\(dp\),随便找一条直径出来,\(f_{i,0/1}\)表示\(i\)子树有没有用过魔法的最大值,树\(dp\)完在链上差不多的\(dp\)一遍就好了,代码还挺难写的。

复杂度\(O(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('\n');}

#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 = 2e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7;

int dep[maxn],head[maxn],tot,n,nxt[maxn],id[maxn],vis[maxn],f[maxn][2],g[maxn][2],h[maxn][2],val[maxn],rt;
struct edge{int to,nxt,w;}e[maxn<<1];

void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}

void dfs(int x,int fa) {
    if(dep[x]>dep[rt]) rt=x;nxt[x]=fa;
    for(int i=head[x];i;i=e[i].nxt)
        if(e[i].to!=fa) dep[e[i].to]=dep[x]+e[i].w,dfs(e[i].to,x);
}

void dp(int x,int fa) {
    int mx1=0,mx2=0,ww,p;
    for(int i=head[x];i;i=e[i].nxt)
        if(e[i].to!=fa&&!vis[e[i].to]) {
            dp(e[i].to,x);int t=f[e[i].to][0]+e[i].w;
            f[x][0]=max(f[e[i].to][0]+e[i].w,f[x][0]);
            if(t>=mx1) mx2=mx1,mx1=t,ww=e[i].w,p=e[i].to;
            else if(t>mx2) mx2=t;
        }
    if(mx1==mx2) f[x][1]=f[x][0];
    else f[x][1]=min(max(mx2,mx1-ww),max(mx2,f[p][1]+ww));
}

void solve() {
    read(n);
    for(int i=1,x,y,z;i<n;i++) read(x),read(y),read(z),ins(x,y,z);
    dep[1]=0;dfs(1,0);int sz=0;dep[rt]=0;dfs(rt,0);
    for(int u=rt;u;u=nxt[u]) id[++sz]=u,vis[u]=1;
    for(int i=1;i<=sz;i++) dp(id[i],0);
    g[1][0]=f[id[1]][0],g[1][1]=f[id[1]][1];
    for(int i=2;i<=sz;i++) {
        int ww;
        for(int j=head[id[i-1]];j;j=e[j].nxt) if(e[j].to==id[i]) ww=e[j].w;//,printf("ww :: %d %d %d\n",id[i-1],id[i],ww);
        g[i][0]=max(g[i-1][0]+ww,f[id[i]][0]);
        g[i][1]=min(max(g[i-1][0],f[id[i]][0]),max(g[i-1][1]+ww,f[id[i]][0]));
        g[i][1]=min(g[i][1],max(g[i-1][0]+ww,f[id[i]][1]));
    }
    h[sz][0]=f[id[sz]][0],h[sz][1]=f[id[sz]][1];int ans=1e9,p;
    for(int i=sz-1;i;i--) {
        int ww;
        for(int j=head[id[i+1]];j;j=e[j].nxt) if(e[j].to==id[i]) ww=e[j].w;
        h[i][0]=max(h[i+1][0]+ww,f[id[i]][0]);
        h[i][1]=min(max(h[i+1][0],f[id[i]][0]),max(h[i+1][1]+ww,f[id[i]][0]));
        h[i][1]=min(h[i][1],max(h[i+1][0]+ww,f[id[i]][1]));
    }
    for(int i=1;i<=sz;i++) {
        //printf("%d ",id[i]);
        // printf("%d %d %d\n",id[i],h[i][0],h[i][1]);
        int tmp=min(max(g[i][0],h[i][1]),max(g[i][1],h[i][0]));
        if(tmp<ans) ans=tmp,p=id[i];
    }//puts("");
    printf("%d %d\n",p,ans);
    // write(ans);
}

void clear() {
    for(int i=0;i<=n;i++) head[i]=g[i][0]=g[i][1]=h[i][0]=h[i][1]=f[i][0]=f[i][1]=vis[i]=0;
    rt=tot=0;
}

int main() {
    int t;read(t);while(t--) solve(),clear();
    return 0;
}

原文地址:https://www.cnblogs.com/hbyer/p/11271941.html

时间: 2024-09-30 22:44:04

HDU校赛 | 2019 Multi-University Training Contest 3的相关文章

杭电2018多校第一场(2018 Multi-University Training Contest 1) 1001.Maximum Multiple (HDU6298)-数学思维题(脑子是个好东西,可惜我没有)

暑假杭电多校第一场,这一场是贪心场,很多贪心的题目,但是自己太菜,姿势挫死了,把自己都写吐了... 2018 Multi-University Training Contest 1 HDU6298.Maximum Multiple 题目意思就是给你一个n,找出来三个数x,y,z, 使得n=x+y+z,而且x,y,z都是n的因数,并且x*y*z为最大值,让你输出来x*y*z的最大值.如果没有满足条件的情况就输出-1. 由1=1/2+1/3+1/6=1/3+1/3+1/3=1/2+1/4+1/4,所

2019 HDOJ Multi-University Training Contest Stage 10(杭电多校)

最后一场多校打得一般般. 题目链接:http://acm.hdu.edu.cn/contests/contest_show.php?cid=857 C: E: I: BFS水题. 1 /* Codeforces Contest 2019_mutc_10 2 * Problem I 3 * Au: SJoshua 4 */ 5 #include <queue> 6 #include <cstdio> 7 #include <vector> 8 #include <s

2019 HDOJ Multi-University Training Contest Stage 8(杭电多校)

中规中矩的一场. 题目链接:http://acm.hdu.edu.cn/contests/contest_show.php?cid=855 C: 定义函数f(d,k)为数字d在数字k中出现的次数.给定d和x,找到尽量大的k使得k<=x且f(d,k)==k. 很诡异的一题,最好的做法仍然是打表找规律.题解给了一个很神奇的结论:满足条件的k<1011且k的分布非常稀疏. 1 /* basic header */ 2 #include <bits/stdc++.h> 3 /* defin

2019 HDOJ Multi-University Training Contest Stage 2(杭电多校)

服务器时不时爆炸,有点难受. 题目链接:http://acm.hdu.edu.cn/userloginex.php?cid=849 A: 神仙题.不可做题. B: dp. C: 推式子题. D: 边分治. E: 可以数学推理的题.但是显然打表更快找出规律.对打出来的结果做两次差分即可. 1 /* basic header */ 2 #include <bits/stdc++.h> 3 /* define */ 4 #define ll long long 5 #define dou doubl

2019 HDOJ Multi-University Training Contest Stage 4(杭电多校)

很抱歉过了这么多天才补这场,最近真的挺忙的…… 出题人是朝鲜的(目测是金策工业?),挺难. 题目链接:http://acm.hdu.edu.cn/contests/contest_show.php?cid=851 A: 签到题. 对于当前的点,若其编号为偶数,则可与1相连使得边权贡献为0.否则从低位向高位找当前点编号的二进制表示的第一个0,使这个0变为1,其他位置变为0并检查新的数字是否小于等于n.若小于等于n则贡献为0,反之贡献为1. 1 /* basic header */ 2 #inclu

hdu 6299 Balanced Sequence( 2018 Multi-University Training Contest 1 )

1 #include <stdio.h> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cmath> 5 #include <string> 6 #include <cstring> 7 #include <algorithm> 8 #include <stack> 9 #include <queue> 10 #include <

杭电2018多校第一场(2018 Multi-University Training Contest 1) 1008.RMQ Similar Sequence (HDU6305) -笛卡尔树+数学期望

6305.RMQ Similar Sequence 这个题的意思就是对于A,B两个序列,任意的l,r,如果RMQ(A,l,r)=RMQ(B,l,r),B序列里的数为[0,1]的实数,B的重量为B的所有元素的和,否则为0.问你B的期望重量是多少. dls讲题说是笛卡尔树,笛卡尔树是一种特定的二叉树数据结构,具体的看这篇博客吧:[pushing my way]笛卡尔树 这个题就是笛卡尔树同构的问题,假设A的笛卡尔树的子树大小为sz[u],那么序列B与A同构的概率为,因为B中的数满足均匀分布(因为B中

ACM多校联赛7 2018 Multi-University Training Contest 7 1009 Tree

[题意概述] 给一棵以1为根的树,树上的每个节点有一个ai值,代表它可以传送到自己的ai倍祖先,如果不存在则传送出这棵树.现在询问某个节点传送出这棵树需要多少步. [题解] 其实是把"弹飞绵羊"那道题从序列上搬到了树上,解法其实类似. 我们可以用LCT维护传送的关系,若点i存在ai倍祖先,那么就把他们link起来,否则就把i与特殊节点n+1给link起来. 询问某个点要传送多少次时,就是询问这个点到n+1有多远,我们在LCT上取出这一段,查询size即可. 1 #include<

2019 Nowcoder Multi-University Training Contest 1 H-XOR

由于每个元素贡献是线性的,那么等价于求每个元素出现在多少个异或和为$0$的子集内.因为是任意元素可以去异或,那么自然想到线性基.先对整个集合A求一遍线性基,设为$R$,假设$R$中元素个数为$r$,那么任取一个不在$R$内的元素,$R$中肯定存在一种取法能和这个元素异或和为$0$.同理,取定一个不在$R$内的元素,再随便取另外任意个不在$R$内的元素,$R$内仍然存在一种取法使得这个异或和为$0$.那么每个不在$R$内的元素包含在$2^{n - r - 1}$个集合内(其他不在$R$内的元素可以