2019-2020 ICPC Asia Hong Kong Regional Contest(补题中)

加粗:赛时AC 

普通:赛后AC

 

B. Binary Tree

轮到某个人时他拿去的数目一定是奇数,判断n奇偶即可。

 

C. Constructing Ranches(点分治)

参考的是这篇文章

 多边形的各边和大于最大边的两倍。

考察树上所有路径的问题点分治是一种常见做法,用点分治然后维护点到根节点的最大值和路径权值,将计算的数字按照最大值进行排序,然后用一个数据结构维护即可。

#include<iostream> 
#include<cstdio>
#include<string>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<algorithm>
#include<queue>
#define N 200050
#define ll long long
using namespace std;
ll T,n;
ll a[N],b[N];
ll heads[N],tot,rt,k;
ll vis[N];
ll sz[N],sum;
ll ans;
ll dp[N];
ll C[N];
pair<ll, int> p[N], val[N];
//��� 
inline void read(ll &p)
{
    p=0;
    ll f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') p=p*10+(ch-'0'),ch=getchar();
    p*=f;
}

struct edge{
    int v,nxt;
}ed[N<<1];

inline int lb(int x) { return x & (-x); }

inline void addin(int u,int v)
{
    ed[++tot].v=v;
    ed[tot].nxt=heads[u];
    heads[u]=tot;
}

inline void getroot(int u,int fa)
{
    sz[u]=1;
    dp[u]=0;
    for(int i=heads[u];i!=0;i=ed[i].nxt)
    {
        int v=ed[i].v;
        if(vis[v]||v==fa) continue;
        getroot(v,u);
        sz[u]+=sz[v];
        dp[u]=max(dp[u],sz[v]);
    }
    dp[u]=max(dp[u],sum-sz[u]);
    if(dp[u]<dp[rt]) rt=u;
}
ll cnt;
inline void add_dfs(int u,int mx,ll w,int fa)
{
    cnt++;
    p[cnt] = {w, cnt};
    val[cnt].first=mx;
    for(int i=heads[u];i!=0;i=ed[i].nxt)
    {
        int v=ed[i].v;
        if(vis[v]||v==fa) continue;
        add_dfs(v,max(1ll*mx,a[v]),w+a[v],u);
    }
}

inline void addv(int x,int v)
{
    while(x<=cnt)
    {
        C[x]+=v;
        x+=lb(x);
    }
    
 } 

inline int query(int x)
{
    int sum=0;
    while(x)
    {
        sum+=C[x];
        x-=lb(x);
    }
    return sum;
}

inline ll cal(int u,int w)
{
    cnt=0;
    add_dfs(u,max(1ll*w,a[u]),w+a[u],0);
    int hd = (w ? w : val[1].first);
    sort(p+1,p+1+cnt);
    for(int i=1;i<=cnt;i++) val[p[i].second].second=i;
    for(int i=0;i<=cnt;i++) C[i]=0;
    ll res=0;
    sort(val+1,val+1+cnt);
    for(int i=1;i<=cnt;i++)
    {
        ll sw=2LL * val[i].first+hd - p[val[i].second].first;
        int l=1,r=cnt,as=0;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(p[mid].first<=sw)
            {
                l=mid+1;
                as=mid;
            }
            else r=mid-1;
        }
        res+=i-1-query(as);
        addv(val[i].second,1);
    }
    return res;
}

inline void go(int u)
{
    vis[u]=1;
    ans+=cal(u,0);
    for(int i=heads[u];i!=0;i=ed[i].nxt)
    {
        int v=ed[i].v;
        if(vis[v]) continue;
        ans-=cal(v,a[u]);
        rt=0;
        dp[0]=sum=sz[v];
        getroot(v,0);
        go(rt);
    }
}

inline void init()
{
    for(int i=0;i<=n;i++) heads[i]=0,vis[i]=0;
    tot=0;ans=0;
}

inline void solve()
{
    read(n);
    init();
    for(int i=1;i<=n;i++)  read(a[i]);
    for(int i=1;i<n;i++)
    {
        ll x,y;
        read(x);read(y);
        addin(x,y);
        addin(y,x);
    }
    rt=0;
    dp[0]=sum=n;
    getroot(1,0);
    go(rt);
    printf("%lld\n",ans);
    
}

int main()
{
    read(T);
    while(T--)
    {
        solve();
    }
    return 0;
}
View Code

 

D. Defining Labels

壕哥过的,本质还是进制转换,只不过答案输出时要进行偏移。

E. Erasing Numbers

数据n为5e3,可以用n2完成。那么我们枚举每个数字,由于数字各不相同,所以我们把大于当前数字的数标记为1,小于的标记为1。根据题意,当+1和-1的数字相等时,一定可以留下该数字,那么我们就从左到右扫描,记录+1和-1的个数,然后记录两个数字的可删除范围,判断两者是否可能相等即可,这个过程最好用类似于栈的方式去维护,有+1和-1相邻就直接消去,因为有可能出现原本没有连续的三个数字,删去之后产生的情况。

听说这题的n可以给的更大,然后用线段树维护,逮捕

#include<iostream> 
#include<cstdio>
#include<string>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<algorithm>
#include<queue>
#define N 1000010
#define ll long long
using namespace std;
ll T,n;
ll a[N],b[N],ans[N];
//快读 
inline void read(ll &p)
{
    p=0;
    ll f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') p=p*10+(ch-'0'),ch=getchar();
    p*=f;
}

int main()
{
    read(T);
    while(T--)
    {
        read(n);
        for(int i=1;i<=n;i++) read(a[i]);
        for(int i=1;i<=n;i++)
        {
            
            int totp1=0,totp2=0,tot11=0,tot22=0,tot1=0,tot2=0;
            int pos=0;
            for(int j=1;j<=n;j++)
            {
                if(a[j]>i)
                {
                    tot11++;
                    tot2=  tot2>0 ? tot2-1 : 0;
                    b[j]=1;
                    tot1++;
                    if(tot1>=3) tot1-=2,totp1+=2;
                }
                if(a[j]<i)
                {
                    tot22++;
                    tot1=  tot1>0 ? tot1-1 : 0;
                    b[j]=-1;
                    tot2++;
                    if(tot2>=3) tot2-=2,totp2+=2;
                }
                if(a[j]==i)
                {
                    pos=j;
                    b[j]=0; 
                    tot2=0;
                    tot1=0;
                }
            }
            
            if(tot22>=tot11)
            {
                if(tot22-totp2<=tot11) ans[pos]=1;
                else ans[pos]=0;
            }
            else
            {
                if(tot11-totp1<=tot22) ans[pos]=1;
                else ans[pos]=0;
            }
        }
        for(int i=1;i<=n;i++) printf("%d",ans[i]);
        printf("\n");
    }
    return 0;
}

/*
11
11 6 3 8 4 9 2 7 10 1 5 




*/
View Code

G. Game Design

杰哥壕哥说他们做过,还说是水题,我就没管了,可恶啊,队友什么时候背着我偷偷优秀了。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <stack>
#include <queue>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#include <cmath>

using namespace std;
typedef long long ll;
#define finc(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define fdec(i,a,b) for(int i=(int)(b);i-->(int)(a);)
#define reset(a,...) a=decltype(a)(__VA_ARGS__)
#define endl '\n'
#define endb ' '
#define read(a,str) scanf("%"#str,&a)
#define print(a,str) printf("%"#str,a)

vector<int> ans;
vector<int> edge;
void f(int val, int now, int cnt)
{
    if (cnt & 1)
        ans.push_back(val);
    else
        ans.push_back(val + 1);
    cnt >>= 1;
    if (cnt == 0)
        return;
    ans.push_back(1), ans.push_back(1);
    edge.push_back(now), edge.push_back(now + 1);
    edge.push_back(now);
    f(val - 1, now + 3, cnt);
}

void ac()
{
    int k; cin >> k;
    if (k == 1)
    {
        cout << 2 << endl;
        cout << 1 << endl;
        cout << 101 << endb << 100 << endl;
        return;
    }
    f(100, 1, k);
    cout << ans.size() << endl;
    for (auto& I : edge)
        cout << I << endb;
    cout << endl;
    for (auto& I : ans)
        cout << I << endb;
    cout << endl;
}

int main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int test = 1; //cin >> test;
    while (test--)
        ac();

    return 0;
}
View Code

I. Incoming Asteroids

这题最后还剩一个小时的时候出的解法,但是打WA了,答案异或的时候带上了k,结果RE了,最后是杰哥补完的题。

不过这题能出解法还算不错了。

主要切入点是每个人最多有1~3个相机,如果每来一次事件2都找一遍哪个人完成了是n2的做法。

如果一个人只有一个相机,那么我们每个天文台使用一个堆就能够优化做法,但是有的人有多个相机,事情就变的棘手起来了。

我们考虑给每个相机分配任务,假如有2个相机就每个分配 $ \frac y 2 $ 的任务,3个就分配$ \frac y 3 $的任务(向上取整),然后将任务放进对应堆里面,很显然如果每个相机都没完成自己的任务,那么这个人一定没有完成,如果有一个相机完成了,我们看3个相机录制的总时间是否符合要求(时间标记在天文台上,后面来的任务标记为原任务时间+天文台时间标记),如果符合标记完成输出,然后再遇到这个人的任务时就不做,否则的话,就用y-掉总的已录制时间,然后用这个值重新分配任务,行分配的任务一定比原本还在堆里的任务先完成,这样就将时间复杂度降为了 $ O(mlogylogn) $.

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <stack>
#include <queue>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#include <cmath>

using namespace std;
typedef long long ll;
#define finc(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define fdec(i,a,b) for(int i=(int)(b);i-->(int)(a);)
#define reset(a,...) a=decltype(a)(__VA_ARGS__)
#define endl '\n'
#define endb ' '
#define read(a,str) scanf("%"#str,&a)
#define print(a,str) printf("%"#str,a)

struct Node
{
    ll val;
    int id;
    Node() :val(0), id(0) {}
    Node(ll _val, int _id) :val(_val), id(_id) {}

    bool operator>(const Node& x)const
    {
        return val > x.val;
    }
};
struct Data :public vector<int>
{
    ll val;
    int size;
    Data() :val(0), size(0) {}
    Data(ll _val, int _size, vector<int>& _vec) :val(_val), size(_size), vector<int>(_vec) {}
};

int n, m;
vector<bool> visited;
vector<Data> query;
vector<ll> top;
vector<priority_queue<Node, vector<Node>, greater<Node>>> buc;


void ac()
{
    read(n, d), read(m, d);
    reset(buc, n + 1), reset(top, n + 1), reset(visited, m + 1), reset(query, 1);
    int ans = 0;
    while (m--)
    {
        int flag; read(flag, d);

        if (flag == 1)
        {
            int y, k;
            read(y, d), read(k, d);
            y ^= ans;
            vector<int> vec(k);
            finc(i, 0, k)
                read(vec[i], d), vec[i] ^= ans;
            ll sum = 0;
            finc(i, 0, k)
                buc[vec[i]].push({ top[vec[i]] + (y + k - 1) / k,(int)query.size() }), sum += top[vec[i]];
            query.push_back({ sum + y,k,vec });
            continue;
        }

        int x, y; read(x, d), read(y, d), x ^= ans, y ^= ans;
        top[x] += y;
        ans = 0;
        vector<int> out;
        while (!buc[x].empty())
        {
            auto now = buc[x].top();
            if (visited[now.id])
            {
                buc[x].pop();
                continue;
            }
            if (now.val > top[x])
                break;
            buc[x].pop();

            ll cnt = 0;
            for (auto& I : query[now.id])
                cnt += top[I];
            if (cnt >= query[now.id].val)
                ans++, visited[now.id] = 1, out.push_back(now.id);
            else
            {
                now.val = (query[now.id].val - cnt + query[now.id].size - 1) / query[now.id].size;
                for (auto& I : query[now.id])
                    buc[I].push({ now.val + top[I], now.id });
            }
        }
        if (ans == 0)
            cout << ans << endl;
        else
        {
            sort(out.begin(), out.end());
            cout << ans << endb;
            finc(i, 0, out.size() - 1)
                cout << out[i] << endb;
            cout << out.back() << endl;
        }
    }
}

int main()
{
    //ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int test = 1; //cin >> test;
    while (test--)
        ac();

    return 0;
}
View Code

J. Junior Mathematician

壕哥写得,据说是数位DP,队友会了就相当于我会了(

#include <iostream>
#include <cstdio>
using namespace std;
const int N=5e3+10;
const int mod=1e9+7;
#define ll long long
char s1[N],s2[N];
ll dp[N][60][60];
int a1[N],a2[N],m,g[N],l1,l2;
int dfs(int i,int j,int k,int p,int kind)
{
    if (!i)
    {
        if (k==0)
            return 1;
        else
            return 0;
    }
    if (!p&&(dp[i][j][k]!=-1))
        return dp[i][j][k];
    int maxx,h;
    if (p)
    {
        if (kind==0)
            maxx=a1[i];
        else
            maxx=a2[i];
    }
    else
        maxx=9;
    ll now=0;
    for (h=0; h<=maxx; h++)
    {
        int nowk=(k+j*h%m-h*g[i]%m+m)%m;
        int nowp,hh;
        if (kind==0)
            hh=a1[i];
        else
            hh=a2[i];
        if (p&&h==hh)
            nowp=1;
        else
            nowp=0;
        now=(now+dfs(i-1,(j+h)%m,nowk,nowp,kind))%mod;
    }
    if(!p)
        dp[i][j][k]=now;
    return now;
}
void clean()
{
    int i,j,k;
    g[1]=1;
    for (i=2; i<=l2; i++)
        g[i]=g[i-1]*10%m;
    for (i=1; i<=l2; i++)
        for (j=0; j<=m; j++)
            for (k=0; k<=m; k++)
                dp[i][j][k]=-1;
}
int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        getchar();
        scanf("%s%s",s1,s2);
        scanf("%d",&m);
        int i,j,k;
        for (l1=0; s1[l1]; l1++) {}
        for (l2=0; s2[l2]; l2++) {}
        for (i=0; i<l1; i++)
            a1[l1-i]=s1[i]-'0';
        for (i=1; i<=l1; i++)
            if (a1[i]>0)
            {
                a1[i]--;
                break;
            }
            else
                a1[i]=9;
        for (i=0; i<l2; i++)
            a2[l2-i]=s2[i]-'0';
        clean();
        int ans1=dfs(l1,0,0,1,0);
        int ans2=dfs(l2,0,0,1,1);
        printf("%d\n",(ans2-ans1+mod)%mod);
    }
    return 0;
}

 
View Code

 

posted @ 2022-05-07 09:45  ztlsw  阅读(38)  评论(0编辑  收藏  举报