题解:
第一题:
#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); }
第二题:解法一:
以下是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; }
解法二: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]); } }
第三题:题中有一个性质, 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); }
今天终于当了一次战力巅峰,贴一张图