2019 杭电多校(第三场)

1002 Blow up the city (支配树)

http://acm.hdu.edu.cn/showproblem.php?pid=6604

题意

给你个DAG图 然后若干次询问 每次询问给你两个点 问你去掉某个点使这量两个点不能到达最终点

进阶版 https://blog.csdn.net/sdut_jk17_zhangming/article/details/98069924

思路

去掉不能到达 即给定点是去掉点的支配点 建支配树即可

代码

#include 

using namespace std;
const int maxn = 1e5+10;
vector G[maxn];
vector E[maxn];
vector T[maxn];
int fa[maxn][20],deep[maxn];
int dfn[maxn],in[maxn];
int n,m;
int ans[maxn];
void init()
{
    memset(in,0,sizeof(in));
    for(int i = 0;i <= n;i++)
    {
        E[i].clear(),G[i].clear(),T[i].clear();
    }
}
int LCA(int u,int v)
{
    if(deep[u] < deep[v]) swap(u,v);
    for(int i = 18;i >= 0;i--)
    {
        if(deep[fa[u][i]] >= deep[v])
            u = fa[u][i];
    }
    if(u == v) return u;
    for(int i = 18;i >= 0;i--)
    {
        if(fa[u][i] != fa[v][i])
        {
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[u][0];
}
void solve(int u)
{
    int x = G[u][0];
    for(int i = 1;i < G[u].size();i++)
    {
        x = LCA(x,G[u][i]);
    }
    T[x].push_back(u);
    deep[u] = deep[x]+1;
    fa[u][0] = x;
    for(int j = 1;j <= 18;j++)
    {
        fa[u][j] = fa[fa[u][j-1]][j-1];
    }
}
void topsort()
{
    for(int i = 1;i <= n;i++)
    {
        if(in[i] == 0)
        {
            G[i].push_back(0);
            E[0].push_back(i);
        }
    }
    queue q;
    q.push(0);
    deep[0] = 0;
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        for(int i = 0;i < E[x].size();i++)
        {
            int y = E[x][i];
            in[y]--;
            if(in[y]<= 0)
            {
                q.push(y);
                solve(y);
            }
        }
    }
}
void dfs(int u,int num)
{
    ans[u] = num;
    for(int i = 0;i < T[u].size();i++)
    {
        int v = T[u][i];
        dfs(v,ans[u]+1);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i = 1;i <= m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            in[u]++;
            E[v].push_back(u);
            G[u].push_back(v);
        }
        topsort();
        dfs(0,1);
        int qw;
        scanf("%d",&qw);
        while(qw--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            int w = LCA(u,v);
            int sum = ans[u] + ans[v] - ans[w] - 1;
            printf("%d\n",sum);
        }
    }
    return 0;
}

1004 Distribution of books

http://acm.hdu.edu.cn/showproblem.php?pid=6606

题意

给你n个数 让你从前面取若干数 分成k个区间 让区间最大值最小

思路

最大值最小 二分

 

#include

using namespace std;
typedef long long ll;
const ll maxn = 2e5 + 10;
const ll inf = 1e18;
ll a[maxn],b[maxn];
int tree[maxn*4];
int n,k,tot;
void build(int x,int l,int r)
{
    tree[x] = 0;
    if(l == r) return ;
    int mid = (l + r) / 2;
    build(x*2,l,mid);
    build(x*2+1,mid+1,r);
}
int query(int x,int l,int r,int L,int R)
{
    if(L <= l&&R >= r) return tree[x];
    int mid = (l + r) / 2;
    int res = 0;
    if(L <= mid) res = max(query(x*2,l,mid,L,R),res);
    if(R > mid) res = max(res,query(x*2+1,mid+1,r,L,R));
    return res;
}
void update(int x,int l,int r,int pos,int val)
{
    if(l == r)
    {
        tree[x] = max(val,tree[x]);
        return ;
    }
    int mid = (l + r) / 2;
    if(pos <= mid) update(x*2,l,mid,pos,val);
    if(pos > mid) update(x*2+1,mid+1,r,pos,val);
    tree[x] = max(tree[x*2],tree[x*2+1]);
}

int check(ll mid)
{
    build(1,1,tot);
    ll sum=0,mxsum=0;
    for(int i=1;i<=n;i++){
        sum+=a[i];
        if(sum-mid>mxsum) continue;
        int pos=lower_bound(b+1,b+1+tot,sum-mid)-b;
        int dp=query(1,1,tot,pos,tot)+1;

        pos=lower_bound(b+1,b+1+tot,sum)-b;
        update(1,1,tot,pos,dp);
        mxsum=max(mxsum,sum);
        if(dp>=k)return 1;
    }
    return 0;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        b[0] = 0;
        for(int i = 1;i <= n;i++)
        {
            scanf("%lld",&a[i]);
            b[i] = b[i-1] + a[i];
        }
        sort(b+1,b+1+n);
        tot = unique(b+1,b+1+n) - (b+1);
        ll l = -inf,r = inf;
        while(l + 1 < r)
        {
            ll mid = (l + r) / 2;
            if(check(mid))
            {
                r = mid;
            }
            else l = mid;
        }
        if(check(l)) printf("%lld\n",l);
        else printf("%lld\n",r);
    }
    return 0;
}

1006 Fansblog (数论定理 威尔逊定理)

http://acm.hdu.edu.cn/showproblem.php?pid=6608

题意

给你一个素数P 让你求Q!%Q   Q是小于P的最大素数

思路

威尔逊定理 : 对于一个素数P (p-1)! ≡ -1(p)

可以求出(P-1)! 除去(P-1)比Q多的

#include 

using namespace std;
typedef long long ll;
ll ksc(ll x,ll y,ll p){//计算x乘y的积
    ll res=0;//加法初始化
    while(y){
        if(y&1)res=(res+x)%p;//模仿二进制
        x=(x<<1)%p; y>>=1;//将x不断乘2达到二进制
    }return res;
}
ll qpow(ll x,ll n,ll mod)
{
    ll ans = 1;
    while(n)
    {
        if(n % 2 == 1)
        {
            ans = ksc(ans,x,mod) % mod;
        }
        x = ksc(x,x,mod) % mod;
        n /= 2;
    }
    return ans;
}

int ok(ll x)
{
    int qw = sqrt(x);
    for(int i = 2; i <= qw;i++)
    {
        if(x % i == 0) return 0;
    }
    return 1;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll p,q;
        scanf("%lld",&p);
        ll ans = p - 1;;
        for(ll i = p-1;i >= 1;i--)
        {
            if(ok(i))
            {
                printf("%lld\n",ans);
                break;
            }
            ans = (ksc(ans,qpow(i,p-2,p),p))%p;
        }
    }
    return 0;
}

1007 Find the answer (权值线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=6609

题意

给你n个数 问你1 - i(1<=i<=n) 去掉多少个数和小于等于m

思路

对于每个位置,求出需要减掉的数 然后在权值线段树上进行二分找答案。

代码

#include 

using namespace std;
typedef long long ll;
const int MAX = 200005;

struct node
{
    ll num,sum;
}tree[MAX*4];
int n,m,nn;
ll a[MAX],w[MAX];
ll ans;
void build(int rt,int l,int r)
{
    tree[rt].num = tree[rt].sum = 0;
    if(l==r) return ;
    int mid = (l + r) / 2;
    build(rt*2,l,mid);
    build(rt*2+1,mid+1,r);
}
void updata(int rt,int l,int r,int x)
{
    if(l == r&&l == x)
    {
        tree[rt].num++;
        tree[rt].sum += a[x];
        return ;
    }
    int mid = (l + r) / 2;
    if(mid >= x) updata(rt*2,l,mid,x);
    else updata(rt*2+1,mid+1,r,x);
    tree[rt].num = tree[rt*2].num + tree[rt*2+1].num;
    tree[rt].sum = tree[rt*2].sum + tree[rt*2+1].sum;
}
void query(int rt,int l,int r,ll need)
{
    if(l == r)
    {   ans += need / a[l];
        if(need%a[l]) ans++;
        return ;
    }
    int mid = (l+r)/2;
    if(tree[rt*2+1].sum >= need)
    {
        query(rt*2+1,mid+1,r,need);
    }
    else
    {
        ans += tree[rt*2+1].num;
        query(rt*2,l,mid,need-tree[rt*2+1].sum);
    }

}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&nn,&m);
        for(int i = 1;i <= nn;i++)
        {
            scanf("%lld",&a[i]);
            w[i] = a[i];
        }
        sort(a+1,a+1+nn);
        n = unique(a+1,a+1+nn) - (a+1);
        build(1,1,n);
        ll sum = 0;
        for(int i = 1;i <= nn;i++)
        {
            sum += w[i];
            if(sum <= m)
            {
                printf("0 ");
                int x = lower_bound(a+1,a+1+n,w[i]) - (a);
                updata(1,1,n,x);
            }
            else
            {
                ll need = sum - m;
                ans = 0;
                query(1,1,n,need);
                printf("%lld ",ans);
                int x = lower_bound(a+1,a+1+n,w[i]) - (a);
                updata(1,1,n,x);
            }
        }
        printf("\n");
    }
    return 0;
}

 

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