51Nod 算法马拉松24

来源:互联网 发布:iosapp开发需要mac 编辑:程序博客网 时间:2024/04/29 05:15

A : 构造
B : 状压DP
C : 构造
D : 线段树或平衡树
E : 树链剖分+线段树
F : Unfinished


A 1804 小C的多边形

强行猜了一个结论,试了一下小数据发现没问题,那就假装没问题吧……就是外面一圈1~n-1,里面把1插在n-2和n-1之间,其他的顺次递推。

本题考察输出优化的使用。

#include<cstdio>using namespace std;namespace runzhe2000{    int n, last = 1, sum, tot; char buff[20000000];    void print_char(char c){buff[++tot] = c;}    void print_int(int x)    {        if(x>9)print_int(x/10);        buff[++tot] = (x%10+'0');    }    void print_close(){puts(buff+1);}    void main()    {        scanf("%d",&n); n--; if(~n&1){puts("0");return;} sum = 3*(n+1)>>1;        for(int i = 1; i <= n; i++) print_int(i),print_char(' '); print_char('\n');        for(int i = 1; i <= n; i++) print_int(last = sum - ((i-1+n)%n?(i-1+n)%n:n) - last),print_char(' ');        print_close();    }}int main(){    runzhe2000::main();}

B 1779 逆序对统计

按数字从小到大做,记f[i][s]表示做到第i小的数字,此时已经填完的状态为s,枚举这个i填不填即可。

这样是O(2nm)的,理论上应该是可以过的,然而本机测了两种大同小异的大数据,一种全是1~20的正序循环的数据1s-跑出,另一种全是20~1的逆序循环7s+跑出。看了一下操作次数发现并没有什么问题,就很纳闷了。后来研究了一下,发现把可用状态丢进队列的话,内存访问很不连续,还不如直接顺序枚举所有状态……论不懂常数的危害QAQ

#include<cstdio>#include<cstring>#include<algorithm>#define N 22#define M 105#define cmax(u,v) ((u)<(v)?(u)=(v):0)using namespace std;namespace runzhe2000{    const int INF = 1<<29;    int n, m, f[2][1<<N], cur, popcount[1<<N], happy;    void main()    {        happy = scanf("%d%d",&n,&m);        for(int i = 0; i < (1<<n); i++) popcount[i] = __builtin_popcount(i);        memset(f, -63, sizeof(f)); f[cur][0] = 0;        for(int i = 1, pos; i <= m; i++, cur ^= 1)        {            happy = scanf("%d",&pos);            int *fc = f[cur], *fcc = f[cur^1], p = 1<<(pos-1);            for(int s = (1<<n)-1; ~s; s--)            {                int v = fc[s];                cmax(fcc[s], v);                 if(~s&p)                {                    int ss = s | p, tmp = v + popcount[s>>pos];                    cmax(fcc[ss], tmp);                }                fc[s] = -INF;            }        }        printf("%d\n",f[cur][(1<<n)-1]);    }}int main(){    runzhe2000::main();}

C 1851 俄罗斯方块

看上去好像非常复杂,实际上用这些方块已经能弄出很多图形了……首先一个显然的结论是奇数个1不可能完成,以下讨论均默认偶数个1。

考虑我们用一个T形的和一个Z形的即可构出如下的反转方案
100
100

同样,用一个L形的和一个Z形的即可构出如下的反转方案
010
100

也就是说,如果不考虑边界,我们可以把一个1直接挪到它的八个邻点之一。理论上如果边界无限远则任意一种局面都可行。考虑边界是怎样的,不妨设n<=m,易证如果n>=2并且m>=3就一定可以。考虑更小的边界,对于2×2的暴力判一下即可。剩下的,对于n=1的情况手动用I形的覆盖一下即可……

#include<cstdio>#include<algorithm>#define N 10000005using namespace std;namespace runzhe2000{    int read01(){char c = getchar(); for(; c != '0' && c != '1'; c = getchar()); return c - '0';}    int a[N], n, m, T;    void main()    {        scanf("%d",&T);        for(; T--; )        {            int cnt = 0, siz = 0; scanf("%d%d",&n,&m);            for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) cnt += (a[++siz] = read01());            if(cnt&1) puts("No");            else            {                if((n>=2 && m>=3) || (m>=2 && n>=3)) puts("Yes");                else if(n == 2 && m == 2) puts((cnt&&cnt!=4)?"No":"Yes");                else                {                    n > m ? m = n: 0;                    if(m <= 3) puts(cnt?"No":"Yes");                    else                    {                        for(int i = 1, ii = m-3; i <= ii; i++)                             if(a[i])                            {                                cnt -= a[i] + a[i+1] + a[i+2] + a[i+3];                                a[i] ^= 1; a[i+1] ^= 1; a[i+2] ^= 1; a[i+3] ^= 1;                                cnt += a[i] + a[i+1] + a[i+2] + a[i+3];                            }                        puts(cnt?"No":"Yes");                    }                }            }        }    }}int main(){    runzhe2000::main();}

D 1680 区间求和

考虑已经知道区间[l,r]的答案,现在在r后面加入a[i] (r+1=i),区间[l,i]的答案会变成什么。记区间[l,r]的答案为sum,c表示[l,r]里面比a[i]小的数的个数,s表示[l,r]里面比a[i]大的数的和,则推一下发现[l,i]的答案是 sum+(c+1)*a[i]+s。

推广下去,考虑已经知道了区间[l,r]以及其所有子区间的答案,同样加入一个a[i],考虑区间[l,i]以及其所有子区间的答案会变成什么。同样推一下得到答案是:sum+a[j]>a[i]ja[j]+(a[k]<a[i]k+i)a[i]

做法口胡完了QAQ。实际上对于后者,要维护的信息还是很多,比如轻边的子树内黑点个数,区间奇数层取反完值会变化多少等等……

不得不说51Nod的评测机是真的快,本机极限数据跑了差不多10s,我还他以为卡两个log。正在绝望之际,交一发,1.5s就过出来了……其实大概是本机太慢了吧,这个电脑连打字都越来越卡了……

#include<cstdio>#define N 200005using namespace std;namespace runzhe2000{    typedef long long ll;    int read()    {        int r = 0; char c = getchar();        for(; c < '0' || c > '9'; c = getchar());        for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar());        return r;    }    int n, m, last[N], ecnt, c[N], top[N], siz[N], fa[N], son[N], dep[N], beg[N], rebeg[N], end[N], timer;    struct edge{int next, to;}e[N<<1];    void addedge(int a, int b){e[++ecnt] = (edge){last[a], b}; last[a] = ecnt;}    void dfs1(int x)    {        dep[x] = dep[fa[x]] + 1; siz[x] = 1; for(int i = last[x]; i; i = e[i].next)        {int y = e[i].to; if(y == fa[x]) continue;fa[y] = x; dfs1(y); siz[x] += siz[y]; siz[y] > siz[son[x]] ? son[x] = y : 0;}    }    void dfs2(int x)    {        rebeg[beg[x] = ++timer] = x; top[x] = son[fa[x]]==x?top[fa[x]]:x; if(son[x]) dfs2(son[x]);        for(int i = last[x]; i; i = e[i].next){int y = e[i].to; if(y == son[x] || y == fa[x]) continue;dfs2(y);}end[x] = timer;    }    struct seg    {        int siz[2], siz_bla[2], rev[2]; ll mod[2], val;    }t1[N*5], t2[N*5];    /***************************************************************************************************************/    void pushup1(int x)    {        seg *ls = &t1[x<<1], *rs = &t1[x<<1|1];        for(int i = 0; i != 2; i++)        {            t1[x].siz[i] = ls->siz[i] + rs->siz[i];            t1[x].siz_bla[i] = ls->siz_bla[i] + rs->siz_bla[i];        }    }    void pushdown1(int x)    {        seg *ls = &t1[x<<1], *rs = &t1[x<<1|1];        for(int i = 0; i != 2; i++) if(t1[x].rev[i])        {            ls->siz_bla[i] = ls->siz[i] - ls->siz_bla[i], rs->siz_bla[i] = rs->siz[i] - rs->siz_bla[i];            ls->rev[i] ^= 1, rs->rev[i] ^= 1, t1[x].rev[i] = 0;        }    }    void build1(int x, int l, int r)    {        t1[x].rev[0] = t1[x].rev[1] = 0;        if(l == r)        {            int id = rebeg[l], d = (dep[id]&1);            t1[x].siz[d] = 1;                   t1[x].siz[!d] = 0;            t1[x].siz_bla[d] = c[id];           t1[x].siz_bla[!d] = 0;            return;        }        int mid = (l+r)>>1; build1(x<<1,l,mid); build1(x<<1|1,mid+1,r); pushup1(x);    }    int query1_siz_bla(int x, int l, int r, int ql, int qr, int d)    {        if(ql <= l && r <= qr) return t1[x].siz_bla[d]; int mid = (l+r)>>1, ret = 0; pushdown1(x);        if(ql <= mid) ret += query1_siz_bla(x<<1,l,mid,ql,qr,d); if(mid<qr) ret += query1_siz_bla(x<<1|1,mid+1,r,ql,qr,d); return ret;    }    int query1_siz_bla(int x, int l, int r, int ql, int qr)    {            if(ql <= l && r <= qr) return t1[x].siz_bla[0]+t1[x].siz_bla[1]; int mid = (l+r)>>1, ret = 0; pushdown1(x);        if(ql <= mid) ret += query1_siz_bla(x<<1,l,mid,ql,qr); if(mid<qr) ret += query1_siz_bla(x<<1|1,mid+1,r,ql,qr); return ret;    }    int query1_siz(int x, int l, int r, int ql, int qr, int d)    {        if(ql <= l && r <= qr) return t1[x].siz[d]; int mid = (l+r)>>1, ret = 0; pushdown1(x);        if(ql <= mid) ret += query1_siz(x<<1,l,mid,ql,qr,d); if(mid<qr) ret += query1_siz(x<<1|1,mid+1,r,ql,qr,d); return ret;    }    void modi1(int x, int l, int r, int ql, int qr, int d)    {        if(ql <= l && r <= qr) {t1[x].rev[d] ^= 1; t1[x].siz_bla[d] = t1[x].siz[d] - t1[x].siz_bla[d]; return;} int mid = (l+r)>>1;        pushdown1(x); if(ql <= mid) modi1(x<<1,l,mid,ql,qr,d); if(mid < qr) modi1(x<<1|1,mid+1,r,ql,qr,d); pushup1(x);          }    /***************************************************************************************************************/    void pushup2(int x)    {        seg *ls = &t2[x<<1], *rs = &t2[x<<1|1];        for(int i = 0; i != 2; i++)        {            t2[x].siz[i] = ls->siz[i] + rs->siz[i];            t2[x].siz_bla[i] = ls->siz_bla[i] + rs->siz_bla[i];            t2[x].mod[i] = ls->mod[i] + rs->mod[i];            t2[x].val = ls->val + rs->val;        }    }    void pushdown2(int x)    {        seg *ls = &t2[x<<1], *rs = &t2[x<<1|1];        for(int i = 0; i != 2; i++) if(t2[x].rev[i])        {            ls->siz_bla[i] = ls->siz[i] - ls->siz_bla[i], rs->siz_bla[i] = rs->siz[i] - rs->siz_bla[i];            ls->rev[i] ^= 1, rs->rev[i] ^= 1, t2[x].rev[i] = 0;            ls->val += ls->mod[i], rs->val += rs->mod[i];            ls->mod[i] *= -1, rs->mod[i] *= -1;        }    }    void build2(int x, int l, int r)    {        t2[x].rev[0] = t2[x].rev[1] = 0;        if(l == r)        {            int id = rebeg[l], d = (dep[id]&1);            t2[x].siz[d] = 1; t2[x].siz[!d] = 0;            t2[x].siz_bla[d] = query1_siz_bla(1,1,n,beg[id],beg[id]);             t2[x].siz_bla[!d] = 0;            for(int i = last[id]; i; i = e[i].next)            {                int y = e[i].to; if(y == son[id] || y == fa[id]) continue;                t2[x].siz[d] += query1_siz(1,1,n,beg[y],end[y],d);                t2[x].siz[!d] += query1_siz(1,1,n,beg[y],end[y],!d);                 t2[x].siz_bla[d] += query1_siz_bla(1,1,n,beg[y],end[y],d);                t2[x].siz_bla[!d] += query1_siz_bla(1,1,n,beg[y],end[y],!d);            }            t2[x].mod[d] = (t2[x].siz[d] - 2ll * t2[x].siz_bla[d]) * id;            t2[x].mod[!d] = (t2[x].siz[!d] - 2ll * t2[x].siz_bla[!d]) * id;            t2[x].val = (ll)(t2[x].siz_bla[d] + t2[x].siz_bla[!d]) * id;            return;        }        int mid = (l+r)>>1; build2(x<<1,l,mid); build2(x<<1|1,mid+1,r); pushup2(x);    }    ll query2(int x, int l, int r, int ql, int qr)    {        if(ql <= l && r <= qr) return t2[x].val; int mid = (l+r)>>1; ll ret = 0; pushdown2(x);        if(ql <= mid) ret += query2(x<<1,l,mid,ql,qr); if(mid < qr) ret += query2(x<<1|1,mid+1,r,ql,qr); return ret;    }    void modi2(int x, int l, int r, int ql, int qr, int d)    {        if(ql <= l && r <= qr)         {            t2[x].siz_bla[d] = t2[x].siz[d] - t2[x].siz_bla[d];            t2[x].rev[d] ^= 1;            t2[x].val += t2[x].mod[d];            t2[x].mod[d] *= -1;            return;        }        int mid = (l+r)>>1; pushdown2(x);         if(ql <= mid) modi2(x<<1,l,mid,ql,qr,d); if(mid < qr) modi2(x<<1|1,mid+1,r,ql,qr,d); pushup2(x);    }    void update2(int x, int l, int r, int p)    {        if(l == r) {build2(x,l,r); return;} int mid = (l+r)>>1; pushdown2(x);        if(p <= mid) update2(x<<1,l,mid,p); else update2(x<<1|1,mid+1,r,p); pushup2(x);    }    /***************************************************************************************************************/    void main()    {        n = read(), m = read();        for(int i = 1; i <= n; i++) c[i] = read();        for(int i = 1, a, b; i <  n; i++)            addedge(a = read(), b = read()), addedge(b,a);        dfs1(1); dfs2(1); build1(1,1,n); build2(1,1,n);        for(int t = 1, op, x; t <= m; t++)        {            op = read(), x = read();            if(op == 1)            {                int d = (dep[x]&1)^1;                modi1(1,1,n,beg[x],end[x],d);                for(int tmp = top[x]; fa[tmp]; tmp = top[fa[tmp]]) update2(1,1,n,beg[fa[tmp]]);                modi2(1,1,n,beg[x],end[x],d);            }            else if(op == 2)            {                int d = (dep[x]&1);                modi1(1,1,n,beg[x],beg[x],d); update2(1,1,n,beg[x]);                for(int tmp = top[x]; fa[tmp]; tmp = top[fa[tmp]]) update2(1,1,n,beg[fa[tmp]]);            }            else             {                ll ans = (ll)x * query1_siz_bla(1,1,n,beg[x],end[x]);                for(int tmp = x, son = x; tmp; tmp = fa[son = top[tmp]])                {                    if(tmp != x) ans += (ll)tmp * (query1_siz_bla(1,1,n,beg[tmp],end[tmp]) - query1_siz_bla(1,1,n,beg[son],end[son]));                    if(tmp != top[tmp]) ans += query2(1,1,n,beg[top[tmp]],beg[tmp]-1);                }                printf("%lld\n",ans);            }        }    }}int main(){    runzhe2000::main();}
0 0