• 2018CCPC吉林赛区 hdu6555~hdu6566


    2018CCPC吉林赛区(重现赛)- 感谢北华大学

    A

    基础数论。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    
    int main() {
        int T,cc = 0;
        scanf("%d",&T);
        while(T --) {
            int n;
            scanf("%d",&n);
            int ans = 0;
            for(int i = 1,r;i <= n;i = r + 1) {
                r = n / (n / i);
                ans += (r-i+1ll) * (n / i) & 1;
            }
            if(ans&1) printf("Case %d: odd
    ",++ cc);
            else printf("Case %d: even
    ",++ cc);
        }
    }
    
    

    B

    基础模拟。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    
    int main() {
        int T,cc = 0;
        scanf("%d",&T);
        map<string,int> mp;
        mp["Beijing"] = 8;
        mp["Washington"] = -5;
        mp["London"] = 0;
        mp["Moscow"] = 3;
        while(T --) {
            int h,m;
            string s,name1,name2;
            scanf("%d:%d",&h,&m);
            cin >> s >> name1 >> name2;
            h %= 12;
            if(s == "PM") h += 12;
            int delta = mp[name2] - mp[name1];
            h += delta;
            //cout << h << endl;
            string rq;
            if(h >= 24) rq = "Tomorrow";
            else if(h < 0) rq = "Yesterday";
            else rq = "Today";
            h += 24; h %= 24;
            string ans;
            if(h <= 11) ans = "AM";
            else ans = "PM",h -= 12;
            if(h == 0) h = 12;
            printf("Case %d: %s %d:%02d %s
    ",++ cc,rq.c_str(),h,m,ans.c_str());
        }
    }
    
    

    C

    基础贪心。也可以写并查集。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef pair<int,int> pii;
    const int SZ = 2e5 + 10;
    
    int bel[SZ],tot,sum,mark[SZ];
    vector<int> g[SZ];
    
    void dfs(int u,int c) {
        bel[u] = c;
        for(int v : g[u]) {
            dfs(v,c);
        }
    }
    
    int main() {
        int T,cc = 0;
        scanf("%d",&T);
        while(T --) {
            int n;
            scanf("%d",&n);
            for(int i = 1;i <= tot;i ++) {
                bel[i] = 0;
                mark[i] = 0;
                g[i].clear();
            }
            tot = n,sum = 0;
    
            priority_queue<pii> q;
            for(int i = 1;i <= n;i ++) {
                int x;
                scanf("%d",&x);
                q.push(make_pair(x,i));
            }
            while(q.size()) {
                pii p = q.top(); q.pop();
                if(p.first <= 1) { mark[p.second] = 1; sum ++; continue; }
                if(q.size()) {
                    pii p2 = q.top(); q.pop();
                    if(p2.first == p.first) {
                        pii ans = make_pair(p.first-1,++ tot);
                       //printf("%d -> %d
    ",tot,p.second);
                       // printf("%d -> %d
    ",tot,p2.second);
                        g[tot].push_back(p.second);
                        g[tot].push_back(p2.second);
                        q.push(ans);
                    }
                    else q.push(p2);
                }
            }
            if(sum < 2) {
                printf("Case %d: NO
    ",++ cc);
            }
            else {
                printf("Case %d: YES
    ",++ cc);
                int t = 0;
                for(int i = 1;i <= tot;i ++) {
                    if(mark[i]) {
                        dfs(i,t);
                        if(t==0) t++;
                    }
                }
                for(int i = 1;i <= n;i ++) printf("%d",bel[i]); puts("");
            }
        }
    }
    
    

    D

    基础概率DP。由于会加1.5%所以状态要乘2。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef pair<int,int> pii;
    const int SZ = 2e5 + 10;
    
    double f[333];
    
    
    int main() {
        int T,cc = 0;
        scanf("%d",&T);
        while(T --) {
            int pp;
            scanf("%d",&pp);
            double p = 1.0*pp/100;
            f[200] = 1/p;
            for(int i = 199;i >= 4;i --) {
                int nx1 = min(200,i+4);
                int nx2 = min(200,i+3);
                f[i] = p * (i/200.0+(1-i/200.0)*(f[nx1]+1))
                      + (1-p) * (f[nx2] + 1);
            }
            printf("Case %d: %.10f
    ",++ cc,f[4]);
        }
    }
    
    
    

    E

    推公式数学题。解方程。直接套求根公式比魔改求根公式的精度要高(?)

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int MAXN=1e3+10;
    const int mod=1e9+7;
    const double eps=1e-7;
    
    int sgn(double a){
        if (fabs(a)<eps) return 0;
        if (a>0) return 1;
        return -1;
    }
    
    int main(){
        int T,cas=0; scanf("%d",&T);
        while(T--){
            double r,h;
            scanf("%lf%lf",&r,&h);
            double ppx,ppy,ppz,ddx,ddy,ddz;
            scanf("%lf%lf%lf",&ppx,&ppy,&ppz);
            scanf("%lf%lf%lf",&ddx,&ddy,&ddz);
            long double px=ppx,py=ppy,pz=ppz,dx=ddx,dy=ddy,dz=ddz;
            long double ox=px,oy=py,oz=pz;
            long double k = r*r/h/h;
            long double a = dx * dx + dy * dy - k * dz * dz;
            long double b = 2 * (dx * ox + dy * oy - k * dz * (oz - h));
            long double c = ox * ox + oy * oy - k * (oz - h) * (oz - h);
            long double discrim = b * b - 4 * a * c;
            long double rootDiscrim = sqrt(discrim);
            /*long double q;
            if (b < 0) q = (-b + rootDiscrim)/2;
            else q = (-b - rootDiscrim)/2;
            long double t0 = q / a;
            long double t1 = c / q;
            long double ans=min(t0,t1);
            if(ans < 1e-8) ans = 0;*/
            long double ans = (-b-rootDiscrim)/2/a;
            printf("Case %d: %.10f
    ",++cas,(double)ans);
        }
        return 0;
    }
    
    

    F

    因为左端点递增,所以 i 包含 k 那么 j 一定包含 k,所以 j 取 i-1 最优,每个点的答案就是 x-2。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef pair<int,int> pii;
    const int SZ = 2e5 + 10;
    const int mod = 1e9+7;
    
    LL read() {
        LL n = 0;
        char a = getchar();
        bool flag = 0;
        while(a > '9' || a < '0') { if(a=='-') flag = 1; a = getchar(); }
        while(a <= '9' && a >= '0') { n=n*10+a-'0'; a = getchar(); }
        if(flag) n=-n;
        return n;
    }
    
    int main() {
        int T = read(),cc = 0;
        while(T --) {
            int n = read(),ans = 0;
            for(int i = 1;i <= n;i ++) {
                int x = read();
                x = max(x-2,0);
                ans ^= x;
            }
            printf("Case %d: %d
    ",++ cc,ans);
        }
    }
    
    

    G

    题意:给 (10^4) 个一欧姆的电阻。定义一个元件:

    1. 一个一欧姆电阻是一个元件
    2. 两个元件并联是一个元件
    3. 两个元件串联是一个元件

    构造一个元件,使得其电阻阻值与 (r) 的绝对值之差小于 (10^{-7})

    key:随机,乱搞

    有连分数做法,不过不太会……

    众所周知 n 个 a 欧姆的电阻并联的电阻是 a/n。想要得到一个尽量小的电阻那么一定是若干个一欧姆电阻并联。

    考虑把 r 拆分成若干个 1/ki,这其实是埃及分数。我们的目标是使得 (sum k_i le 10^4)

    考虑加入一个 1/ki,那么能算出 ki 的下界。每次选下界的贪心是不优的,而我们只需要找到一个较优解。

    实际上只需要给下界加一个随机数调整,跑若干遍直到满足条件即可。实测大概跑个几遍就有了,随机了 (10^5) 组都能出解。

    输出比较坑

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef pair<int,int> pii;
    const int SZ = 2e5 + 10;
    const int mod = 1e9+7;
    
    LL read() {
        LL n = 0;
        char a = getchar();
        bool flag = 0;
        while(a > '9' || a < '0') { if(a=='-') flag = 1; a = getchar(); }
        while(a <= '9' && a >= '0') { n=n*10+a-'0'; a = getchar(); }
        if(flag) n=-n;
        return n;
    }
    
    mt19937 rd(2333);
    
    LL randlr(LL l,LL r)  {
        return rd()%(r-l+1)+l;
    }
    
    vector<int> a;
    
    int work(double r) {
        a.clear();
        double now = 0;
        int sum = 0;
        while(fabs(now-r) > 1e-9) {
            int k = 1/(r-now); if((r-now)*k<1) k++;
            k += randlr(0,5);
            now += 1.0/k;
            sum += k;
            a.push_back(k);
          //  printf("%.10f %d
    ",now,k);
        }
       // puts("finish");
        return sum;
    }
    
    int main() {
        int T = read(),cc = 0;
        while(T --) {
    //        double r = randlr(1e7,9e7)/1e7;
            double r;
            scanf("%lf",&r);
            printf("Case %d:
    ",++ cc);
            for(int i = 1;;i ++){
                int sum = work(r);
                if(sum <= 1e4) {
                    int m = sum - 1;
                    printf("%d %d
    ",sum,m);
                    int t = sum-1,lst = 0;
                 //   for(int x : a) cout << x << " "; puts("");
                    vector<int> b;
                    for(int x : a) {
                        printf("1 %d %d
    ",lst,lst+1);
                        lst+=2; t ++; x --;
                        while(x -- > 1) printf("1 %d %d
    ",lst,t),lst++,t++;
                        b.push_back(t);
                    }
                    int x = a.size();
                    if(x>1) {
                        printf("0 %d %d
    ",b[0],b[1]); t++;
                        for(int j = 2;j < b.size();j ++)
                            printf("0 %d %d
    ",b[j],t),t++;
                    }
                    break;
                }
            }
        }
    }
    
    

    H

    基础线段树。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef pair<int,int> pii;
    const int SZ = 2e5 + 10;
    const int mod = 1e9+7;
    
    LL read() {
        LL n = 0;
        char a = getchar();
        bool flag = 0;
        while(a > '9' || a < '0') { if(a=='-') flag = 1; a = getchar(); }
        while(a <= '9' && a >= '0') { n=n*10+a-'0'; a = getchar(); }
        if(flag) n=-n;
        return n;
    }
    
    int mi[SZ];
    
    struct seg {
        int l,r;
        int sum,misum;
        int x,rx,len;
    }tree[SZ*4];
    
    void update(int p) {
        tree[p].sum = (tree[p<<1].sum+tree[p<<1|1].sum) % mod;
        tree[p].misum = (tree[p<<1].misum+tree[p<<1|1].misum) % mod;
    }
    
    void build(int p,int l,int r) {
        tree[p].l = l;
        tree[p].r = r;
        tree[p].sum = 0;
        tree[p].misum = 0;
        tree[p].x = 0;
        tree[p].rx = 0;
        tree[p].len = 0;
        if(l == r) {
            tree[p].misum = 1;
            return ;
        }
        int mid = l + r >> 1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        update(p);
    }
    
    void pushc(int p,int x,int rx,int len) {
        tree[p].sum = (1ll*mi[len]*tree[p].sum%mod+1ll*x*(tree[p].r-tree[p].l+1)%mod
            + 1ll*rx*tree[p].misum%mod*mi[len]%mod) % mod;
        tree[p].misum = 1ll*mi[len*2]*tree[p].misum % mod;
        tree[p].x = (1ll*tree[p].x*mi[len]%mod + x) % mod;
        tree[p].rx = (tree[p].rx + 1ll*rx*mi[tree[p].len] % mod) % mod;
        tree[p].len += len;
    }
    
    void pushdown(int p) {
        if(tree[p].len) {
            pushc(p<<1,tree[p].x,tree[p].rx,tree[p].len);
            pushc(p<<1|1,tree[p].x,tree[p].rx,tree[p].len);
            tree[p].len = 0;
            tree[p].x = 0;
            tree[p].rx = 0;
        }
    }
    
    void change(int p,int l,int r,int d) {
        if(l<=tree[p].l&&tree[p].r<=r) {
            pushc(p,d,d,1);
            return ;
        }
        pushdown(p);
        int mid = tree[p].l + tree[p].r >> 1;
        if(l <= mid) change(p<<1,l,r,d);
        if(mid < r) change(p<<1|1,l,r,d);
        update(p);
    }
    
    int ask(int p,int l,int r) {
        if(l<=tree[p].l&&tree[p].r<=r) {
            return tree[p].sum;
        }
        pushdown(p);
        int mid = tree[p].l + tree[p].r >> 1,ans = 0;
        if(l <= mid) (ans += ask(p<<1,l,r)) %= mod;
        if(mid < r) (ans += ask(p<<1|1,l,r)) %= mod;
        return ans;
    }
    
    int main() {
        mi[0] = 1;
        for(int i = 1;i <= 2e5;i ++) mi[i]=mi[i-1]*10ll%mod;
        int T = read(),cc = 0;
        while(T--) {
            int n = read(),m = read();
            build(1,1,n);
            printf("Case %d:
    ",++ cc);
            while(m --) {
                char s[6];
                scanf("%s",s);
                int l = read(),r = read();
                if(s[0] == 'w') {
                    int d = read();
                    change(1,l,r,d);
                }
                else {
                    printf("%d
    ",ask(1,l,r));
                }
            }
        }
    }
    
    

    I

    要么全打完,那么肯定用刚好打过这个怪的打他。要么不打完,那么防御怪都不打,剩下的田忌赛马。

    J

    题意:给 n 个球, m 个颜色,给出每个球染每个颜色的权值。染完色之后要重排成一个环,使得存在一组重排方案使得任意两个相邻球颜色不同。求权值极差最小值。 (n,m le 2000,a_{i,j}le 10^6)

    key:尺取

    题意即为任意颜色不能用超过 n/2 次。

    考虑枚举最小值,找到对应的最小的最大值。现在即如何判定是否合法。

    如果已知了最小值和最大值,现在要判定。

    显然每个球要至少有一个可选颜色。

    如果一个球只有一个颜色可选,那么这个球就只能是这个颜色。也就是说对于每个颜色,必选它的球的数目必须小于等于 n/2。现在所有的颜色必选它的球的数目都满足条件,如果对于所有颜色,可选它的球的数目小于等于 n/2,那么一定存在一组方案(显然);否则,即存在一个颜色,可选它的球的数目大于 n/2,以下分类讨论:

    1. 当 n 是偶数时,因为必选它的球的数目小于等于 n/2,那么我们可以恰好选它 n/2个,用其它颜色补剩下的(因为其他颜色不可能大于n/2)。
    2. 当 n 是奇数时,此时补全 n/2 后,剩下的球全选另一个颜色会出问题。而这种情况只会出现在仅用两个颜色时(如果用大于等于三种颜色,那么一定有一个可选颜色选第三种,不会出现这种情况)。

    仔细观察上述的充要条件,我们我们只需要维护这么几个东西:

    1. 没有可选颜色的球的个数
    2. 对于每个颜色,必选它的球的个数
    3. 有多少个颜色,必选它的个数大于 n/2
    4. 有多少个颜色可选

    对权值排序做双指针,每次是单点插入和删除,上述几个都可以 (O(1)) 实现。(对于每个球,加入颜色和删除颜色是按权值递增的;对于每个颜色,每次是必选它的球的个数加一或减一),所以瓶颈就是排个序。你可以用桶排做到 (O(10^6+nm)),不过没必要。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<int,LL> pil;
    const int SZ = 2e5 + 10;
    const int mod = 1e9+7;
    
    LL read() {
        LL n = 0;
        char a = getchar();
        bool flag = 0;
        while(a > '9' || a < '0') { if(a=='-') flag = 1; a = getchar(); }
        while(a <= '9' && a >= '0') { n=n*10+a-'0'; a = getchar(); }
        if(flag) n=-n;
        return n;
    }
    
    int a[SZ],num,lim,colNum,col2[SZ];
    
    void addCol(int x) {
       // printf("add color: %d
    ",x);
        a[x] ++;
        if(a[x] == lim) num ++;
    }
    
    void delCol(int x) {
       // printf("del color: %d
    ",x);
        if(a[x] == lim) num --;
        a[x] --;
    }
    
    int noMatchNumber;
    queue<int> cols[SZ];
    
    void init(int n,int m) {
        for(int i = 1;i <= n;i ++) {
            while(cols[i].size()) cols[i].pop();
        }
        noMatchNumber = n;
        for(int i = 1;i <= m;i ++) {
            a[i] = 0;
            col2[i] = 0;
        }
        colNum = 0;
        num = 0;
        lim = n / 2 + 1;
    }
    
    void add(pii p) {
        int id = p.first,col = p.second;
        if(col2[col] == 0) colNum ++;
        col2[col] ++;
        if(cols[id].size() == 0) {
            noMatchNumber --;
            addCol(col);
        }
        else if(cols[id].size() == 1) {
            delCol(cols[id].front());
        }
        cols[id].push(col);
    }
    
    void del(pii p) {
        int id = p.first,col = p.second;
        if(col2[col] == 1) colNum --;
        col2[col] --;
        assert(!cols[id].empty());
        assert(cols[id].front() == col);
        if(cols[id].size() == 1) {
            noMatchNumber ++;
            delCol(cols[id].front());
        }
        else if(cols[id].size() == 2) {
            addCol(cols[id].back());
        }
        cols[id].pop();
    }
    
    int n,m;
    
    bool check() {
        if(noMatchNumber) return false;
        if(num) return false;
        if(n%2==1&&colNum <= 2) return false;
        return true;
    }
    
    int main() {
        int T = read(),cc = 0;
        while(T --) {
            n = read(),m = read();
            init(n,m);
            vector<pair<int,pii> > a;
            for(int i = 1;i <= n;i ++) {
                for(int j = 1;j <= m;j ++) {
                    a.push_back(make_pair(read(),make_pair(i,j)));
                }
            }
            sort(a.begin(),a.end());
            int ans = 1e9;
            //for(int i = 0;i < a.size();i ++) printf("%d: %d %d %d
    ",i,a[i].first,a[i].second.first,a[i].second.second);
            for(int i = 0,j = -1;i < a.size();i ++) {
                while(!check() && j+1 < (int)a.size()) add(a[j+1].second),j ++;
                if(!check()) break;
              //  printf("[%d,%d] %d
    ",i,j,num);
                ans = min(ans,a[j].first - a[i].first);
                del(a[i].second);
            }
            if(ans == 1e9) ans = -1;
            printf("Case %d: %d
    ",++ cc,ans);
        }
    }
    
    /**
    2
    3 3
    1 2 100
    2 1 200
    1 1 300
    
    2 2
    
    1
    5 3
    2 3 7
    2 5 7
    2 7 5
    2 6 5
    7 6 8
    
    
    4 1
    1
    1
    1
    1
    
    
    */
    
    

    K

    辣鸡模拟,咕

    L

    题意:给一个 n 个点的树,每个点有一个重量和价值。可以从树中选出一个独立集,定义 (f(x)) 为总重量为 x 的最大价值的方案数,求所有的 (f(x) (1 le x le m))(n le 50,m le 5000)

    key:搜索,背包

    先放个题解的 (O(n^2m)) 的做法:

    普通树形背包复杂度 O(nm2),不可取。
    考虑在 dfs 序上做 01 背包。

    对整棵树做轻链剖分, dfs 先走轻儿子,最后再走重儿
    子。这样从重儿子子树回溯的时候会直接回到重链顶端
    我们所选独立集的后续发展与这条重链的中间节点是否
    在独立集内没有关系。

    从而背包是我们只要记下该节点的 log(n) 个重链顶端是
    否在独立集内,该状态的大小为 2^log(n) = n。 dpi,mask,m 表
    示走到 i 这个节点, log(n) 个重链顶端的状态为 mask,
    所选重量为 m 的最有方案,直接背包。

    没太懂那个 log 个重链……所以放个乱搞做法。

    考虑折半,瓶颈在于对于两个点集的合并如何 check 是否是独立集。如果能模拟暴力背包的过程,那么只需要记录子树根节点选不选即可,这样合并两个背包是 max 卷积, (O(m^2)) 的复杂度。

    考虑选重心为根节点,对每个子树暴力搜索独立集得到一个背包,之后按子树根节点选不选来讨论合并。这样能保证搜索最坏情况下是 (2^{25}) ,现在来看合并次数。

    假设重心的每个子树大小都是 k ,那么搜索独立集的复杂度是 (O(2^kn/k)) ,迭代合并的复杂度是 (O(nm^2/k)) ,取等号时 k 在 25 左右,如果乘个 T 可能就不太行了。这个最坏情况是链。

    子树比较小时可以用一些常数优化,比如只合并背包中合法的元素,合并子树时从小到大之类。

    然而数据并没有卡这个乱搞所以就200+ms过了,我估计出题人也没想到

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<int,LL> pil;
    const int SZ = 2e5 + 10;
    const int mod = 1e9+7;
    
    LL read() {
        LL n = 0;
        char a = getchar();
        bool flag = 0;
        while(a > '9' || a < '0') { if(a=='-') flag = 1; a = getchar(); }
        while(a <= '9' && a >= '0') { n=n*10+a-'0'; a = getchar(); }
        if(flag) n=-n;
        return n;
    }
    
    int n,m;
    int A[55],B[55];
    int mark[55],xl[55];
    vector<int> nodelist,g[55];
    
    void remark(int u,int f) {
        nodelist.push_back(u);
        for(int v : g[u]) {
            if(v == f) continue;
            remark(v,u);
        }
    }
    
    int sz[55];
    
    void predfs(int u,int f) {
        sz[u] = 1;
        for(int v : g[u]) {
            if(v == f) continue;
            predfs(v,u);
            sz[u] += sz[v];
        }
    }
    
    int get_centroid(int u) {
        predfs(u,0);
        int s = sz[u];
        while(1) {
            int found = 1;
            for(int v : g[u]) {
                if(sz[v] > sz[u]) continue;
                if(sz[v] * 2 >= s) {
                    u = v; found = 0; break;
                }
            }
            if(found) return u;
        }
    }
    
    pil up(pil a,pil b) {
        pil ans;
        ans.first = max(a.first,b.first);
        if(a.first == ans.first) ans.second += a.second;
        if(b.first == ans.first) ans.second += b.second;
        if(!ans.second) ans.first = -1;
        return ans;
    }
    
    pil a[2][5010];
    pil ans[2][5010];
    pil tmp[2][5010];
    
    void dfs(int d,int dn,int S,int sa,int sb) {
        if(sa>m) return ;
        if(d == dn) {
            a[S&1][sa] = up(a[S&1][sa],make_pair(sb,1));
            return ;
        }
        int u = nodelist[d];
        if(!(xl[u] & S)) dfs(d+1,dn,S^(1<<mark[u]),sa+A[u],sb+B[u]);
        dfs(d+1,dn,S,sa,sb);
    }
    
    void work(int u,int r) {
        nodelist.clear();
        remark(u,r);
        for(int i = 0;i < nodelist.size();i ++) mark[nodelist[i]] = i;
        for(int u : nodelist) {
            xl[u] = 0;
            for(int v : g[u]) {
                if(v == r) continue;
                xl[u] ^= 1<<mark[v];
            }
        }
        for(int i = 0;i < 2;i ++)
            for(int j = 0;j <= m;j ++) {
                tmp[i][j] = make_pair(-1,0);
                a[i][j] = make_pair(-1,0);
            }
        dfs(0,nodelist.size(),0,0,0);
        for(int x = 0;x < 2;x ++) {
            for(int i = 0;i <= m;i ++) {
                if(ans[x][i].second == 0) continue;
                for(int y = 0;y < 2;y ++) {
                    if(x==1&&y==1) continue;
                    for(int j = 0;i+j <= m;j ++) {
                        if(a[y][j].second == 0) continue;
                        int sb = ans[x][i].first+a[y][j].first;
                        LL t = ans[x][i].second*a[y][j].second;
                        tmp[x][i+j] = up(tmp[x][i+j],make_pair(sb,t));
                    }
                }
            }
        }
        /*cout << u << endl;
        for(int i = 0;i < 2;i ++) {
            cout << i << endl;
            for(int j = 0;j <= m;j ++) printf("%3d",a[i][j].first); puts("");
            for(int j = 0;j <= m;j ++) printf("%3d",a[i][j].second); puts("");
        }
        for(int i = 0;i < 2;i ++) {
            cout << i << endl;
            for(int j = 0;j <= m;j ++) printf("%3d",ans[i][j].first); puts("");
            for(int j = 0;j <= m;j ++) printf("%3d",ans[i][j].second); puts("");
        }
        for(int i = 0;i < 2;i ++) {
            cout << i << endl;
            for(int j = 0;j <= m;j ++) printf("%3d",tmp[i][j].first); puts("");
            for(int j = 0;j <= m;j ++) printf("%3d",tmp[i][j].second); puts("");
        }
        puts("--------");*/
        for(int i = 0;i < 2;i ++)
            for(int j = 0;j <= m;j ++)
                ans[i][j] = tmp[i][j];
    }
    
    void bl() {
        vector<pil> ans; ans.resize(m+1);
        for(int S = 0;S < (1<<n);S ++) {
            int sb = 0,sa = 0,b = 0;
            for(int i = 0;i < n;i ++) {
                if(S>>i&1) {
                    bool flag = 0;
                    for(int j : g[i+1]) if(S>>(j-1)&1) flag = 1;
                    if(flag) { b=1; break;}
                    sa += A[i+1];
                    sb += B[i+1];
                }
            }
            if(b) continue;
            if(sa>m) continue;
            if(ans[sa].first < sb) ans[sa] = make_pair(sb,1);
            else if(ans[sa].first == sb) ans[sa].second ++;
        }
        for(int i = 1;i <= m;i ++) printf("%lld ",ans[i].second); puts("");
    }
    
    int main() {
        int T = read(),cc = 0;
        while(T --) {
            n = read(),m = read();
            for(int i = 1;i <= n;i ++) A[i]=read(),B[i]=read();
            for(int i = 1;i <= n;i ++) g[i].clear();
            for(int i = 1;i < n;i ++) {
                int x = read(),y = read();
                g[x].push_back(y);
                g[y].push_back(x);
            }
            int rt = get_centroid(1);
            predfs(rt,0);
            sort(g[rt].begin(),g[rt].end(),[](int x,int y) {return sz[x] < sz[y];});
            for(int i = 0;i <= m;i ++) {
                ans[0][i] = ans[1][i] = make_pair(-1,0);
            }
            ans[0][0] = make_pair(0,1);
            ans[1][A[rt]] = make_pair(B[rt],1);
           // cout << rt << endl;
            for(int x : g[rt]) work(x,rt);
            printf("Case %d:
    ",++ cc);
            for(int i = 1;i <= m;i ++) {
                pil x = up(ans[0][i],ans[1][i]);
                printf("%lld%c",x.second,i==m?'
    ':' ');
            }
            //bl();
        }
    }
    
    /**
    1
    4 5
    1 1
    2 2
    3 2
    2 1
    1 2
    2 3
    3 4
    
    3
    3 2
    1 1
    1 1
    1 1
    1 2
    1 3
    4 5
    1 1
    2 2
    3 2
    2 1
    1 2
    2 3
    3 4
    5 10
    3 1
    2 2
    4 4
    7 8
    5 16
    1 2
    1 3
    2 4
    2 5
    */
    
    
  • 相关阅读:
    Python—requests模块详解
    强烈推荐(原创亲测)!!!Fiddler抓取https设置详解(图文)
    dexlib2的源码框架
    Android检测代理
    APP加固反调试(Anti-debugging)技术点汇总
    IDA逆向常用宏定义
    JNI学习积累之一 ---- 常用函数大全
    CMake之CMakeLists.txt编写入门
    Android Project和app中两个build.gradle配置的区别
    更新说明
  • 原文地址:https://www.cnblogs.com/dqsssss/p/11534336.html
Copyright © 2020-2023  润新知