暑假第二十一测

题解:

第一题:

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


const int M = 100005, ME = 1000005;
struct edge{int u, v, w;}G[ME];
int fa[M], siz[M], tot, val[M];
int find(int x){
    if(fa[x] == x)return x;
    return fa[x] = find(fa[x]);
}
bool cmp(edge a, edge b){
    return a.w > b.w;
}
void add(int u, int v, int w){
    G[++tot].u = u; G[tot].v = v; G[tot].w = w;
}
int main(){
    freopen("zoo.in","r",stdin);
    freopen("zoo.out","w",stdout);
    int n, m;
    long long ans = 0;
    scanf("%d%d",&n, &m);
    for(int i = 1; i <= n; i++)scanf("%d", &val[i]);
    int u, v;
    for(int i = 1; i <= m; i++){
        scanf("%d%d", &u, &v);
        add(u, v, min(val[u], val[v]));
    }
    sort(G + 1, G + 1 + tot, cmp);
    for(int i = 1; i <= n; i++) fa[i] = i, siz[i] = 1;
    for(int i = 1; i <= m; i++){
        int u = G[i].u, v = G[i].v;
        if(find(u) == find(v))continue;
        else {
            int x = find(u), y = find(v);
            fa[x] = y;
            ans += 1LL*G[i].w * siz[x] * siz[y] * 2;
            siz[y] += siz[x]; 
        }
    }
    printf("%I64d
", ans);
    
}
View Code

 第二题:解法一:

以下是std:

#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;const int N=2*1e5+10;int n;int m;int T;
map <int,int> mp;
struct treearray
{
    int ta[2*N];
    inline void c(int x,const int& t){for(;x<=n;x+=x&(-x))ta[x]+=t;}
    inline int q(int x){int r=0;for(;x>0;x-=x&(-x))r+=ta[x];return r;}
    inline void clear(){for(int i=0;i<=n;i++)ta[i]=0;}
}ta1,ta2;
struct op{int tp;int l;int r;}op[N];int nu[N];
inline void solve(int z)
{
    scanf("%d",&m);
    for(int i=1;i<=m;i++)scanf("%d%d",&op[i].tp,&op[i].l);
    for(int i=1;i<=m;i++)if(op[i].tp==0){++n,op[i].r=op[i].l+n;nu[n]=i;}
    for(int i=1;i<=m;i++)if(op[i].tp==0)mp[op[i].l]=1,mp[op[i].r]=1;
    map <int,int>:: iterator it1,it;
    for(it=mp.begin(),it1=it,++it1;it1!=mp.end();++it,++it1)it1->second+=it->second;
    for(int i=1;i<=m;i++)if(op[i].tp==0){op[i].l=mp[op[i].l],op[i].r=mp[op[i].r];}
    n=mp.size();
    printf("Case #%d:
",z);
    for(int i=1;i<=m;i++)
    {
        if(op[i].tp==0)
        {
            int x1=ta1.q(op[i].r)-ta1.q(op[i].l-1);int x2=ta2.q(op[i].r)-ta2.q(op[i].l-1);
            int x3=ta1.q(op[i].r)-ta2.q(op[i].l-1);printf("%d
",x1+x2-x3);
            ta1.c(op[i].l,1);ta2.c(op[i].r,1);
        }
        else 
        {int l=op[nu[op[i].l]].l;int r=op[nu[op[i].l]].r;ta1.c(l,-1);ta2.c(r,-1);}
    }
}
inline void clear(){mp.clear();ta1.clear();ta2.clear();n=0;}
int main()
{
    freopen("segment.in","r",stdin);
    freopen("segment.out","w",stdout);
    scanf("%d",&T);for(int z=1;z<=T;z++){solve(z);clear();}
    fclose(stdin);fclose(stdout);return 0;
}
View Code

 解法二:CDQ分治,一维时间,二维插入位置归并递减,三维结束位置树状数组;

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


const int M = 200005;
int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x *= f;
}

struct Point{int x, y, id, v;}p[M], t[M], now[M];
int ans[M], cnt, c[M], Lx, dis[M];
bool no[M];
inline int lowbit(int x){return x & (-x);}
void add(int pos, int v){
    for(int x = pos; x <= Lx; x += lowbit(x))
        c[x] += v;
}
int query(int pos){
    int ret = 0;
    for(int x = pos; x; x -= lowbit(x))
        ret += c[x];
    return ret;
}

void cdq(int lf, int rg){
    if(lf == rg)return ;
    int mid = (lf + rg) >> 1;
    cdq(lf, mid); cdq(mid + 1, rg);
    int i = lf, j = mid + 1, num = lf;
    while(i <= mid && j <= rg){
        if(p[i].x >= p[j].x){
            add(p[i].y, p[i].v); now[num++] = p[i++];
        }
        else {
            if(!no[p[j].id]) ans[p[j].id] += query(p[j].y); 
            now[num++] = p[j++];
        }
    }
    while(j <= rg)ans[p[j].id] += query(p[j].y), now[num++] = p[j++];
    for(int e = lf; e < i; e++)add(p[e].y, -p[e].v);
    while(i <= mid)now[num++] = p[i++];
    for(int e = lf; e <= rg; e++)p[e] = now[e];
}
void init(){
    memset(no, 0, sizeof(no));
    memset(ans, 0, sizeof(ans));
    cnt = 0;
}

int main(){
    freopen("segment.in","r",stdin);
    freopen("segment.out","w",stdout);
    int T, tt=0;
    scanf("%d", &T);
    while(T--){
        init();
        int n = read();
        for(int i = 1; i <= n; i++){
            int opt = read(), y = read();
            if(!opt){
                dis[++cnt] = y + cnt;
                p[i].x = y, p[i].y = y + cnt, p[i].v = 1, p[i].id = i;
                t[cnt] = p[i];
            }
            else {
                p[i] = t[y]; no[i] = 1;
                p[i].v = -1, p[i].id = i;
            }
        }
        sort(dis + 1, dis + 1 + cnt);
        Lx = unique(dis + 1, dis + 1 + cnt) - dis - 1;
        for(int i = 1; i <= n; i++)
            p[i].y = lower_bound(dis + 1, dis + 1 + Lx, p[i].y) - dis;
        cdq(1, n);
        printf("Case #%d:
",++tt);
        for(int i = 1; i <= n; i++)
            if(!no[i])printf("%d
", ans[i]);
    }
}
View Code

第三题:题中有一个性质, k < max(n, m) 所以一定有一行或一列为空,那么我们前年的行都可随便填,最后一行使上面满足就可以了,对于一列也只需要用最后一个满足就可以了所以一行就是2^(剩余格子 - 1);

最后一行满足前面的要求,最后一行也不会矛盾,证明如下:

1。(m + n) % 2 ==1, 方案数为0,;

m行每行要奇数个-1, (-1)^m,n列每列要奇数个-1, (-1)^n, (-1)^n != (-1)^m

2。n, m 为奇数;前偶数行每行奇数个-1,有奇数*偶数个-1 = 偶数个-1,减去 偶数个-1(成对,影响抵消)= 偶数个-1,最后一行就要偶数个1, 那么-1要奇数个, 符合条件;

n,m为偶数,证法同上; 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int M = 1000005;
ll mod;
int n, m, k, len[M], cnt[M];
ll ksm(ll a, ll b){
    ll ret = 1;
    for( ; b; b >>= 1, a = a * a % mod)
        if(b & 1)ret = ret * a % mod;
    return ret;
}


int main(){
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    scanf("%d%d%d", &n, &m, &k);
    int x, y, w;
    ll ans = 1;
    if(n >= m){
        for(int i = 1; i <= n; i++)len[i] = m;
        for(int i = 1; i <= k; i++){
            scanf("%d%d%d", &x, &y, &w);
            len[x]--;
            if(w == -1)cnt[x]++;
        }    
    }
    else {
        swap(n, m);
        for(int i = 1; i <= n; i++)len[i] = m;
        for(int i = 1; i <= k; i++){
            scanf("%d%d%d", &x, &y, &w);
            swap(x, y);len[x]--;
            //fprintf(stderr, "%d %d
", x, y);
            if(w == -1)cnt[x]++;
        }
    }
    scanf("%I64d", &mod);
    if(n % 2 != m % 2){puts("0");return 0;}
    for(int i = 1; i <= n; i++){
        if(len[i] == m){
            for(int j = 1; j <= n; j++){
                if(i == j)continue;
                if(!len[j]){
                    if(cnt[j]%2 == 0){puts("0");return 0;}
                }
                else ans = ans * ksm(2, len[j] - 1) % mod;
            }
            break;
        }
    }
    printf("%I64d
", ans);
}
View Code

今天终于当了一次战力巅峰,贴一张图

原文地址:https://www.cnblogs.com/EdSheeran/p/9513230.html