2011 Multi-University Training Contest 8 - Host by HUST

Rank:56/147.

开场看B,是个线段树区间合并,花了2hour敲完代码。。。再花了30min查错。。发现push_down有问题。改了就AC了。

然后发现A过了很多人。推了个公式,发现是个分段函数。取个中间点代进去结果就AC了。

C好像也很水?看了看原来是个傻逼BFS。A了。

F化解了一下就 集合子集异或为0的种数。想了想没想到什么东西就go die了。

 

A.Liang Guo Sha(阅读理解)

看懂题意后搞出两个式子,然后取个极值就行了。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=100005;
//Code begin...

int main ()
{
    int a, b, c;
    while (~scanf("%d%d%d",&a,&b,&c)){
        double p=((b+c)*1.0)/(a+b+2*c);
        double ans=a*p*p+b*(1-p)*(1-p)-c*(1-p)*p*2;
        printf("%.6f\n",ans);
    }
    return 0;
}
View Code

 

B.Black And White(线段树)

询问区间[l,r]的最长连续黑色的长度。

建立线段树,对每个节点维护6个量,分别表示最长连续黑色,最长连续白色,左边最长连续黑色,左边最长连续白色,右边最长连续黑色,右边最长连续白色。

对于修改操作用tag标记一下。在需要push_down的时候push_down即可AC。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=100005;
//Code begin...

struct SegTree{int lbmax, lwmax, rbmax, rwmax, bmax, wmax;}seg[N<<2];
struct Node{
    int lmax, rmax, ma, siz;
    Node(int _lmax=0, int _rmax=0, int _ma=0, int _siz=0):lmax(_lmax), rmax(_rmax), ma(_ma), siz(_siz){}
};
int a[N];
bool tag[N<<2];

void push_up(int p, int l, int r){
    int lsize=(l+r)/2-l+1, rsize=r-(l+r)/2;
    if (seg[p<<1].lbmax) {
        seg[p].lbmax=(seg[p<<1].lbmax==lsize?seg[p<<1|1].lbmax:0)+seg[p<<1].lbmax;
        seg[p].lwmax=0;
    }
    else {
        seg[p].lwmax=(seg[p<<1].lwmax==lsize?seg[p<<1|1].lwmax:0)+seg[p<<1].lwmax;
        seg[p].lbmax=0;
    }
    if (seg[p<<1|1].rbmax) {
        seg[p].rbmax=(seg[p<<1|1].rbmax==rsize?seg[p<<1].rbmax:0)+seg[p<<1|1].rbmax;
        seg[p].rwmax=0;
    }
    else {
        seg[p].rwmax=(seg[p<<1|1].rwmax==rsize?seg[p<<1].rwmax:0)+seg[p<<1|1].rwmax;
        seg[p].rbmax=0;
    }
    seg[p].bmax=max(max(seg[p<<1].bmax,seg[p<<1|1].bmax),seg[p<<1].rbmax+seg[p<<1|1].lbmax);
    seg[p].wmax=max(max(seg[p<<1].wmax,seg[p<<1|1].wmax),seg[p<<1].rwmax+seg[p<<1|1].lwmax);
}
void push_down(int p){
    if (!tag[p]) return ;
    tag[p<<1]^=1; tag[p<<1|1]^=1; tag[p]=0;
    swap(seg[p].bmax,seg[p].wmax); swap(seg[p].lbmax,seg[p].lwmax); swap(seg[p].rbmax,seg[p].rwmax);
}
void init(int p, int l, int r){
    if (l<r) {
        int mid=(l+r)>>1;
        init(lch); init(rch); push_up(p,l,r); tag[p]=0;
    }
    else {
        if (a[l]) seg[p].lbmax=seg[p].rbmax=seg[p].bmax=1, seg[p].lwmax=seg[p].rwmax=seg[p].wmax=0;
        else seg[p].lwmax=seg[p].rwmax=seg[p].wmax=1, seg[p].lbmax=seg[p].rbmax=seg[p].bmax=0;
        tag[p]=0;
    }
}
void update(int p, int l, int r, int L, int R){
    push_down(p);
    if (L>r||R<l) return ;
    if (L<=l&&R>=r) tag[p]=1, push_down(p);
    else {
        int mid=(l+r)>>1;
        update(lch,L,R); update(rch,L,R); push_up(p,l,r);
    }
}
Node query(int p, int l, int r, int L, int R){
    push_down(p);
    if (L>r||R<l) return Node(0,0,0,0);
    if (L<=l&&R>=r) return Node(seg[p].lbmax,seg[p].rbmax,seg[p].bmax,r-l+1);
    int mid=(l+r)>>1;
    Node x=query(lch,L,R), y=query(rch,L,R), z;
    z.lmax=(x.lmax==x.siz?y.lmax:0)+x.lmax; z.rmax=(y.rmax==y.siz?x.rmax:0)+y.rmax;
    z.ma=max(max(x.ma,y.ma),x.rmax+y.lmax); z.siz=x.siz+y.siz;
    return z;
}
int main ()
{
    int n, m, flag, l, r;
    while (~scanf("%d",&n)) {
        FOR(i,1,n) scanf("%d",a+i);
        init(1,1,n);
        scanf("%d",&m);
        FOR(i,1,m) {
            scanf("%d%d%d",&flag,&l,&r);
            if (flag) update(1,1,n,l,r);
            else {
                printf("%d\n",query(1,1,n,l,r).ma);
            }
        }
    }
    return 0;
}
View Code

 

C.Turn Right(BFS)

题目保证一定存在起点到终点的路径。如果把终点给封死,那么从起点bfs一次再回到起点就行了。沿途统计所有标记。

这题的节点状态与普通的不同,需要定义vis[i][j]表示到点i是以j方向到的。然后对于每个方向会有一个优先级。即总是turn right。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=505;
//Code begin...

int vis[N][N][4], row[N][N], col[N][N];
int ps[4][4]={{3,0,1,2},{0,1,2,3},{1,2,3,0},{2,3,0,1}};

struct Node{
    int x, y, pos;
    Node(int _x=0, int _y=0, int _pos=0):x(_x),y(_y),pos(_pos){}
};
queue<Node>Q;

int main ()
{
    int T, n, m, s, t;
    scanf("%d",&T);
    while (T--) {
        int num=0;
        mem(vis,0);
        scanf("%d%d%d%d",&n,&m,&s,&t);
        FOR(i,1,2*n-1) {
            if (i&1) FO(j,0,m-1) scanf("%d",&col[(i-1)/2][j]);
            else FO(j,0,m) scanf("%d",&row[i/2][j]);
        }
        while (!Q.empty()) Q.pop();
        Q.push(Node(0,s,1)); vis[0][s][1]=1;
        while (!Q.empty()) {
            Node tmp=Q.front(); Q.pop();
            FO(i,0,4) {
                int now=ps[tmp.pos][i];
                if (now==0) {
                    if (tmp.y==0||col[tmp.x][tmp.y-1]) continue;
                    if (vis[tmp.x][tmp.y-1][now]) goto label;
                    Q.push(Node(tmp.x,tmp.y-1,now));
                    vis[tmp.x][tmp.y-1][now]=1;
                    break;
                }
                else if (now==1) {
                    if (tmp.x==n-1||row[tmp.x+1][tmp.y]) continue;
                    if (vis[tmp.x+1][tmp.y][now]) goto label;
                    Q.push(Node(tmp.x+1,tmp.y,now));
                    vis[tmp.x+1][tmp.y][now]=1;
                    break;
                }
                else if (now==2) {
                    if (tmp.y==m-1||col[tmp.x][tmp.y]) continue;
                    if (vis[tmp.x][tmp.y+1][now]) goto label;
                    Q.push(Node(tmp.x,tmp.y+1,now));
                    vis[tmp.x][tmp.y+1][now]=1;
                    break;
                }
                else {
                    if (tmp.x==0||row[tmp.x][tmp.y]) continue;
                    if (vis[tmp.x-1][tmp.y][now]) goto label;
                    Q.push(Node(tmp.x-1,tmp.y,now));
                    vis[tmp.x-1][tmp.y][now]=1;
                    break;
                }
            }
        }
label:  FO(i,0,n) FO(j,0,m) FO(k,0,4) if (vis[i][j][k]) {++num; break;}
        puts(num==n*m?"YES":"NO");
    }
    return 0;
}
View Code

 

F.Game(高斯消元)

要想去除某些石堆使得先手必败。那么s[i]^s[i+1]^...s[n]=0.即问题转化为求出集合S的子集异或和为0的子集种数。

集合S里的每个数,要么选要么不选,考虑每一位的贡献,那么选了这个数,这个数上二进制位为1的位会贡献1.

于是对于每位,建立异或方程组,再用高斯消元求解这个方程的自由变元的数量即可。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=105;
//Code begin...

int equ, var, a[35][N];

LL pow_mod(LL a, LL n, LL mod){
    LL ret=1, temp=a%mod;
    while (n) {
        if (n&1) ret=ret*temp%mod;
        temp=temp*temp%mod;
        n>>=1;
    }
    return ret;
}
int Guass(){
    int row, col;
    for(row=0,col=0; row<equ&&col<var; ++col,++row){
        int max_r=row;
        FO(i,row+1,equ) {
            if(a[row][col]==1) break;
            if(a[max_r][col]<a[i][col]){max_r=i; break;}
        }
        if(max_r!=row) FOR(j,0,var) swap(a[max_r][j],a[row][j]);
        if(a[row][col]==0) row--;
        FO(i,row+1,equ) {
            if(a[i][col]==0) continue;
            FOR(j,col,var) a[i][j]^=a[row][j];
        }
    }
    FO(i,row,equ) if(a[i][col]) return -1;
    return var-row;
}
int main ()
{
    int T, n, val;
    scanf("%d",&T);
    while (T--) {
        mem(a,0);
        scanf("%d",&n);
        equ=31; var=n;
        FO(i,0,n) {
            scanf("%d",&val);
            FO(j,0,equ) a[j][i]=val%2, val/=2;
        }
        FO(j,0,equ) a[j][n]=0;
        int b=Guass();
        printf("%lld\n",pow_mod(2,b,MOD));
    }
    return 0;
}
View Code

 

G.Sequence Decomposition(贪心+树状数组)

给出一个序列,每次可以将连续的一段都减去1,每次操作的长度定义为连续段的长度,问最后使得序列都变为0时,最短的操作长度最长是多少。

首先,将操作改变顺序是不影响答案的。不妨从左端点1开始,依次向后看右端点的最佳选值.

如果有a[i]<=a[i+1],那么右端点就可以从i拓展到i+1了。如果有a[i]>a[i+1].那么右端点就不能再继续拓展了。反证证明这个贪心的正确性。

但是如果直接模拟操作的话显然是超时的。注意到每次的操作实际上是区间减,查询单点。可以用树状数组维护。

复杂度O(nlogn).

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=10005;
//Code begin...

int a[N], tree[N], n;

void add(int x, int val){while (x<=n+1) tree[x]+=val, x+=lowbit(x);}
int query(int x){
    int res=0;
    while (x) res+=tree[x], x-=lowbit(x);
    return res;
}
int main ()
{
    int T, ans;
    scanf("%d",&T);
    while (T--) {
        mem(tree,0); ans=INF;
        scanf("%d",&n);
        FOR(i,1,n) scanf("%d",a+i), add(i,a[i]), add(i+1,-a[i]);
        a[n+1]=0;
        int now=1;
        FOR(i,1,n) {
            if (a[i]<=a[i+1]) continue;
            int tmp=a[i]-a[i+1];
            add(now,-tmp); add(i+1,tmp);
            FOR(j,now,i) if (query(j)>=0) {ans=min(i-j+1,ans); now=j; break;}
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

H.Road constructions(最大权闭合子图)

裸题。。。不明白考试为啥不看。。。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=5005;
//Code begin...

struct Edge{int p, next, w;}edge[500005];
struct Node{int pre, suc, w, id;}node[3005];
int head[N], cnt=2, s, t, vis[N];
int val[N];
queue<int>Q;

void add_edge(int u, int v, int w){
    edge[cnt].p=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++;
    edge[cnt].p=u; edge[cnt].w=0; edge[cnt].next=head[v]; head[v]=cnt++;
}
int bfs(){
    int i, v;
    mem(vis,-1);
    vis[s]=0; Q.push(s);
    while (!Q.empty()) {
        v=Q.front(); Q.pop();
        for (i=head[v]; i; i=edge[i].next) {
            if (edge[i].w>0 && vis[edge[i].p]==-1) {
                vis[edge[i].p]=vis[v] + 1;
                Q.push(edge[i].p);
            }
        }
    }
    return vis[t]!=-1;
}
int dfs(int x, int low){
    int i, a, temp=low;
    if (x==t) return low;
    for (i=head[x]; i; i=edge[i].next) {
        if (edge[i].w>0 && vis[edge[i].p]==vis[x]+1){
            a=dfs(edge[i].p,min(edge[i].w,temp));
            temp-=a; edge[i].w-=a; edge[i^1].w += a;
            if (temp==0) break;
        }
    }
    if (temp==low) vis[x]=-1;
    return low-temp;
}
void init(){mem(head,0); mem(val,0); cnt=2;}
int main ()
{
    int n, m, k;
    while (scanf("%d%d",&n,&m), n+m) {
        int res=0, sum=0, tmp;
        s=0; t=m+1; init();
        FOR(i,1,m) scanf("%d",&tmp), res+=tmp, add_edge(s,i,tmp);
        scanf("%d",&k);
        FOR(i,1,k) scanf("%d%d%d%d",&node[i].pre,&node[i].suc,&node[i].id,&node[i].w), val[node[i].id]+=node[i].w;
        FOR(i,1,k) FOR(j,i+1,k) {
            if (node[i].id==node[j].id) continue;
            if (node[i].suc==node[j].pre) add_edge(node[i].id,node[j].id,INF);
            else if (node[i].pre==node[j].suc) add_edge(node[j].id,node[i].id,INF);
        }
        FOR(i,1,m) add_edge(i,t,val[i]);
        while (bfs()) while (tmp=dfs(s,INF)) sum+=tmp;
        printf("%d\n",res-sum);
    }
    return 0;
}
View Code

 

posted @ 2017-04-18 14:36  free-loop  阅读(169)  评论(0编辑  收藏  举报