2018 China Collegiate Programming Contest Final

A Mischievous Problem Setter

题目链接
题意:n道题,每道题具有难度和时间,按照难度解题,求m分钟解题数量
思路:按顺序计算总和即可

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;

struct node {
    int D, T;
}k[maxn];

int main() {
    int t;
    scanf("%d", &t);
    int ca = 0;
    while (t--) {
        printf("Case %d: ", ++ca);
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &k[i].D);
        }
        for (int i = 1; i <= n; i++) {
            scanf("%d", &k[i].T);
        }
        sort(k + 1, k + 1 + n, [&](node a, node b) {
            return a.D < b.D;
        });
        int cnt = 0;
        for (int i = 1; i <= n; i++) {
            //cout << k[i].D << endl;
            if (m >= k[i].T) {
                m -= k[i].T;
                cnt++;
            }
            else {
                break;
            }
        }
        cout << cnt << endl;
    }
}


/*
2
5 120
5 10 20 35 100
10 20 35 100 100000
13 300
52 55 82 11 62 79 38 8 58 28 1 70 32
27 62 45 77 22 69 34 43 21 43 85 22 36
*/

B Balance of the Force

题目链接
题意:每个人都可以分属为光明或黑暗阵营,对其阵营产生ai和bi的贡献值,要求每个人分属完后的max贡献-min贡献最小。人与人之间有厌恶关系,即两个人厌恶就不能在同一阵营。
思路:通过种类并查集或者DFS染色来区分不同阵营的人。可以形成若干个集合,记录集合最大和最小值,对于一个集合,其存在光明和黑暗两种可能,排序后遍历一维,用线段树记录另一维的最值,当两个集合属于同一个并查集就覆盖取最优情况。

    #include <bits/stdc++.h>

    #define maxn 200005
    #define inf 0x3f3f3f3f
    using namespace std;

    int n,m;

    int cnt,tot;
    int flag=0;
    int fa[maxn];
    int value[maxn];
    int vis[maxn];

    int in_maxx[maxn];
    int in_tree[maxn];

    int find(int x){
        if(x!=fa[x]){
            int t=fa[x];
            fa[x]=find(fa[x]);
            value[x]=(value[x]+value[t])%2;
        }
        return fa[x];
    }

    void mix(int x,int y,int s){
        int fx=find(x);
        int fy=find(y);
        if(fx!=fy){
            fa[fx]=fy;
            value[fx]=value[x]^value[y]^s;
        }else if(value[x]==value[y]){
            flag=1;
        }
    }

    void init(){
        flag=0;
        cnt=0;
        tot=0;
        for(int i=1;i<=n;i++){
            fa[i]=i;
            value[i]=0;
            vis[i]=0;
        }
    }

    struct point{
        int x,y;
    }a[maxn];

    struct node{
        int maxx,minn;
        int id;

        node(int a=inf,int b=-inf,int c=0):minn(a),maxx(b),id(c){}
    }t[maxn<<1];

    bool cmp(node a,node b){
        if(a.minn==b.minn)
            return a.maxx<b.maxx;
        return a.minn>b.minn;
    }

    int tree[maxn<<2];
    void Build(int l,int r,int rt){
        tree[rt]=-inf;
        if(l==r)return;
        int mid=(l+r)>>1;
        Build(l,mid,rt<<1);
        Build(mid+1,r,rt<<1|1);
    }

    void pushup(int rt){
        tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
    } 

    void update(int index,int x,int l,int r,int rt){
        if(l==r){
            tree[rt]=x;
            return;
        }

        int mid=(l+r)>>1;
        if(index<=mid)
            update(index,x,l,mid,rt<<1);
        else
            update(index,x,mid+1,r,rt<<1|1);
        pushup(rt);
    }

    int main(){
        int T;
        scanf("%d",&T);
        for(int cas=1;cas<=T;cas++){
            scanf("%d%d",&n,&m);
            init();

            int u,v;
            for(int i=1;i<=m;i++){
                scanf("%d%d",&u,&v);
                mix(u,v,1);
            }

            for(int i=1;i<=n;i++){
                scanf("%d%d",&a[i].x,&a[i].y);
                if(flag)continue;

                u=find(i);
                if(!vis[u]){
                    cnt+=2;
                    vis[u]=cnt-1;
                    if(!value[i]){
                        t[cnt-1]=node(a[i].x,a[i].x,++tot);
                        t[cnt]=node(a[i].y,a[i].y,tot);
                    }else{
                        t[cnt-1]=node(a[i].y,a[i].y,++tot);
                        t[cnt]=node(a[i].x,a[i].x,tot);
                    }
                    in_tree[tot]=0;
                }else{
                    if(!value[i]){
                        t[vis[u]].minn=min(t[vis[u]].minn,a[i].x);
                        t[vis[u]].maxx=max(t[vis[u]].maxx,a[i].x);

                        t[vis[u]+1].minn=min(t[vis[u]+1].minn,a[i].y);
                        t[vis[u]+1].maxx=max(t[vis[u]+1].maxx,a[i].y);
                    }else{
                        t[vis[u]].minn=min(t[vis[u]].minn,a[i].y);
                        t[vis[u]].maxx=max(t[vis[u]].maxx,a[i].y);

                        t[vis[u]+1].minn=min(t[vis[u]+1].minn,a[i].x);
                        t[vis[u]+1].maxx=max(t[vis[u]+1].maxx,a[i].x);
                    }
                }
            }

            printf("Case %d: ",cas);
            if(flag){
                printf("IMPOSSIBLE\n");
                continue;
            }

            Build(1,tot,1);
            sort(t+1,t+cnt+1,cmp);
            int sum=0,id=0,ans=inf;
            for(int i=1;i<=cnt;i++){

    //            cout<<t[i].minn<<' '<<t[i].maxx<<endl;
                if(sum==tot){
                    if(t[i].maxx<t[in_maxx[t[i].id]].maxx)
                        update(in_tree[t[i].id],t[i].maxx,1,tot,1);
                    ans=min(ans,tree[1]-t[i].minn);
                }else{
                    if(!in_tree[t[i].id]){
                        sum++;
                        in_tree[t[i].id]=++id;
                        in_maxx[t[i].id]=i;
                        update(id,t[i].maxx,1,tot,1);
                        if(sum == tot) ans = min(ans, tree[1] - t[i].minn);
                    }else if(t[i].maxx<t[in_maxx[t[i].id]].maxx)
                        update(in_tree[t[i].id],t[i].maxx,1,tot,1);
                }
            }
            printf("%d\n",ans);
        }
    } 

G Pastoral Life in Stardew Valley

题目链接
题意:在 n×m 的棋盘上选择两个长方形使一个长方形完全包含另一个长方形,求方案数
思路:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const ll maxn = 1e5 + 5;
const ll inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;

ll x3[maxn], x2[maxn], x1[maxn];
void init() {
    x3[0] = 0;
    x2[0] = 0;
    x1[0] = 0;
    for (ll i = 1; i < maxn; i++) {
        x3[i] = (x3[i - 1] + i * i*i%mod) % mod;
        x2[i] = (x2[i - 1] + i * i%mod) % mod;
        x1[i] = (x1[i - 1] + i % mod) % mod;
    //    cout << i << " " << x3[i] << " " << x2[i] << " " << x1[i] << endl;
    }
}


ll qpow(ll A, ll B) {
    ll t = 1;
    while (B) {
        if ((B & 1)) {
            t = t * A%mod;
        }
        A = A * A%mod;
        B = B >> 1;
    }
    return t;
}


ll fun(ll n) {
    ll res = (((mod - x3[n - 2] % mod) % mod + (n - 2)*x2[n - 2] % mod + ((n - 1)*x1[n - 2] % mod) % mod)) % mod;
//    printf("*%d ", res);
    res = res * qpow(2ll, mod - 2) % mod;
    return res;
}

int main() {
    init();
    ll t;
    scanf("%lld", &t);
    int ca = 0;
    while (t--) {
        printf("Case %d: ", ++ca);
        ll n, m;
        scanf("%lld%lld", &n, &m);
        if (n <= 2 || m <= 2)puts("0");
        else printf("%lld\n", fun(n)*fun(m)%mod);
    }
}

I Cockroaches

题目链接
题意:二维平面上有若干只蟑螂,一种工具可以对一个点释放,使同一行和同一列蟑螂都死掉,求最多杀死蟑螂数和方案数。
思路:先求出最多的蟑螂数量,然后通过已知最多的蟑螂数量推出相对应多少中方案数。

    #include<bits/stdc++.h>
    using namespace std;
    using ll = long long;

    const ll maxn = 1e5 + 5;
    const ll inf = 0x3f3f3f3f;
    const ll mod = 1e9 + 7;

    struct Hash {
        ll a[maxn], cnt;
        void init() { cnt = 0; }
        void add(ll x) { a[++cnt] = x; }
        void work() {
            sort(a + 1, a + 1 + cnt);
            cnt = unique(a + 1, a + 1 + cnt) - a - 1;
        }
        ll get(ll x) {
            return lower_bound(a + 1, a + 1 + cnt, x) - a;
        }
    }hsx,hsy;

    ll x[maxn], y[maxn];

    ll numx[maxn], numy[maxn];
    vector<ll>v[maxn];

    ll fun_ans() {
        ll ma = 0;
        ll cnt = 0;
        for (ll i = 1; i <= hsx.cnt; i++) {
            if (ma > numx[i]) {
                continue;
            }
            else if (ma == numx[i]) {
                cnt++;
            }
            else{
                ma = numx[i];
                cnt = 1;
            }
        }
        //cout << ma << "**" << cnt << endl;
        ll res = 0;
        for (ll i = 1; i <= hsy.cnt; i++) {
            ll resy = numy[i];
            ll ct = 0;
            for (ll j : v[i]) {
                if (numx[j] == ma) {
                    ct++;
                }
            }
            if (ct == cnt) {
                res = max(res, ma + numy[i] - 1);
            }
            else {
                res = max(res, ma + numy[i]);
            }
        }

        ll second_cnt = 0;
        for (ll i = 1; i <= hsx.cnt; i++) {
            if (numx[i] == ma - 1) {
                second_cnt++;
            }
        }
        //cout << ma << " ma" << endl;


        ll ans = 0;
        for (ll i = 1; i <= hsy.cnt; i++) {
            ll resy = numy[i];
            //
            ll ct1 = 0, ct2 = 0;
            for (ll j : v[i]) {
                if (numx[j] == ma) {
                    ct1++;
                }
                if (numx[j] == ma - 1) {
                    ct2++;
                }
            }
            if (ct1 == cnt) {
                if(resy + ma - 1 == res)
                    ans += cnt + second_cnt - ct2;
            }
            else {
                if (resy + ma == res)
                    ans += cnt - ct1;
            }
            //cout << ans << " ans:" << endl;
        }
        printf("%lld ", res);
        if (res == 2)return ans / 2;
        else return ans;
    }

    int main() {
        ll t;
        scanf("%lld", &t);
        ll ca = 0;
        while (t--) {
            ll n;
            scanf("%lld", &n);
            hsx.init(); hsy.init();
            for (ll i = 1; i <= n; i++) {
                numx[i] = 0;
                numy[i] = 0;
                v[i].clear();
                scanf("%lld%lld", &x[i], &y[i]);
                hsx.add(x[i]);
                hsy.add(y[i]);
            }
            hsx.work(); hsy.work();
            for (ll i = 1; i <= n; i++) {
                x[i] = hsx.get(x[i]);
                y[i] = hsy.get(y[i]);
                numx[x[i]]++;
                numy[y[i]]++;
                v[y[i]].push_back(x[i]);
            }
            /*cout <<"hsx,hsy:"<< hsx.cnt << " " << hsy.cnt << endl;
            for (ll i = 1; i <= n; i++) {
                cout <<"(i,j) "<< x[i] << "  " << y[i] << endl;
            }*/
            printf("Case %lld: ", ++ca);
            ll ans = fun_ans();
            printf("%lld\n", ans);
        }
    }

    /*
    20
    5
    1 2
    1 3
    2 3
    4 5 
    6 7

    3
    1 2
    2 3
    3 1


    */

J Mr. Panda and Sequence Puzzle

题目链接
RSA解密,待补

L Ultra Weak Goldbach’s Conjecture

题目链接
题意:一个数分为六个素数和,求任意可行解。
思路:题目告诉一个偶数可以分为两个素数,一个奇数可以分为五个素数。
可以想到对于一个偶数可以分为 2+2+2+2+素数+素数。一个奇数可以分为3+2+2+2+素数+素数。枚举一个素数,判另一个素数即可。

    #include <bits/stdc++.h>

    #define maxn 1000005
    typedef long long ll;
    using namespace std;

    ll x;
    int prime[maxn];
    ll p[maxn];
    int tot;

    void init(){
        for(int i=2;i<=1000000;i++){
            if(prime[i]==0)
                p[++tot]=i;
            for(int j=1;j<=tot&&i*p[j]<=1000000;j++){
                prime[i*p[j]]=1;
                if(i%p[j]==0)
                    break;
            }
        }
    }

    bool check(ll x){
        for(ll i=2;i*i<=x;i++){
            if(x%i==0)
                return false;
        }
        return x!=1;
    }

    int main(){
        int t;
        init();
        scanf("%d",&t);
        for(int cas=1;cas<=t;cas++){
            scanf("%lld",&x);
            printf("Case %d: ",cas);
            if(x<=11){
                printf("IMPOSSIBLE\n");
                continue;
            }

            if(x%2==0){
                x-=8;
                for(int i=1;i<=tot;i++){
    //                cout<<i<<" "<<p[i]<<" "<<x-p[i]<<endl;
                    if(check(1ll*(x-p[i])))
                    {
                        printf("%lld %lld 2 2 2 2\n",p[i],1ll*(x-p[i]));
                        break;
                    }
                }
            }else{
                x-=9;
                for(int i=1;i<=tot;i++){
                    if(check(x-p[i]))
                    {
                        printf("%lld %lld 2 2 2 3\n",p[i],1ll*(x-p[i]));
                        break;
                    }
                }
            }
        }
    }