水题记录

  从noip之后,自己的状态就非常不好。学文化课的时候心里总想着竞赛,真的停课了却又异常浮躁,简单题不想做,难题不会做,错了的题也不改,天天打游戏,静不下心。省选也是各种瞎打,day2T1竟然会因为没有memset掉了40分。虽说苟进了队,但毕竟进的不光彩,若是还以这样的状态下去,潦草离场,那当初选择这条路的意义又在哪里?

  得开始好好学习了啊......

 

4.16

  正式停课的第一天~

  昨天的HNOI考的巨炸,今天就先改改题

  (老吴一大早分析了一波局势,dalao_cxy被寄予厚望,Orz,要向他学习)

  ~~~~~

  只改了Day2两道题 http://www.cnblogs.com/XYZinc/p/8854765.html

  还做了一道@cxy出的dp

  今天效率好低啊

 

4.17

  今天就主要打一些基础算法调整一下状态

  ~~~~~

  • 贪心

  「雅礼集训 2017 Day4」洗衣服

  http://www.cnblogs.com/XYZinc/p/8862632.html

 

  「雅礼国庆 2017 Day5」Repulsed

  很容易想到贪心,对于所有未处理的点,在它的第k祖先处处理必然是最优的
  f[i][j]表示节点i的子树中,距离为j且需要灭火器的点数
  r[i][j]表示从节点i出发,可以向距离不大于j的节点分配的灭火器个数

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 #define ll long long
 5 
 6 inline ll read()
 7 {
 8     ll x = 0, f = 1; char ch = getchar();
 9     while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
10     while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
11     return x * f;
12 }
13 
14 int n, s, k, ans;
15 vector<int> to[N];
16 
17 ll f[N][25], r[N][25];
18 void dfs(int x, int fa)
19 {
20     f[x][0] = 1;
21     for(int i = 0; i < to[x].size(); i++)
22     {
23         int kk = to[x][i];
24         if(fa == kk) continue;
25         dfs(kk, x);//从叶子节点向上dp
26         for(int j = 1; j <= k; j++)
27             f[x][j] += f[kk][j - 1], r[x][j - 1] += r[kk][j];
28     }
29     if(f[x][k])
30     {
31         int t = f[x][k] / s + (f[x][k] % s != 0);
32         ans += t; r[x][k] += t * s;
33     }
34     int p = k;
35     for(int i = k; i >= 0; i--)//从下到上处理能覆盖的点
36         while(f[x][i])
37         {
38             while(!r[x][p] && p >= i) p--;
39             if(p < i) break;//不能继续处理,退出
40             int t = min(r[x][p], f[x][i]);
41             r[x][p] -= t; f[x][i] -= t;
42         }
43 }
44 
45 int main()
46 {
47     n = read(); s = read(); k = read();
48     for(int i = 1; i < n; i++)
49     {
50         int x = read(), y = read();
51         to[x].push_back(y); to[y].push_back(x);
52     }
53     dfs(1, 0);
54     ll cnt = 0;//最后一起处理距离根k以内的节点
55     for(int i = 0; i <= k; i++) cnt += f[1][i];
56     ans += cnt / s + (cnt % s != 0);
57     cout << ans;
58     return 0;
59 }
View Code

  

  poj1328 Radar Installation

//在x上方给出n个点,要求用最少个数的半径为i,圆心在x轴上的圆覆盖所有点,输出最少需要的圆的个数,无法覆盖输出-1,多组测试数据

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <cstring>
using namespace std;
const int N = 1005;
const int inf = 2000000000;

int n, ans, T;
int d, x[N], y[N];

struct node
{
    double l, r;
}s[N];

bool cmp(node a, node b)
{
    if(a.l == b.l) return a.r < b.r;
    return a.l < b.l;
}

int main()
{
    while(scanf("%d%d", &n, &d) && n && d)
    {
        T++;
        bool fail = false; ans = 0;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d", &x[i], &y[i]);
            if(y[i] > d) fail = true;
        }
        if(fail) {printf("Case %d: -1\n", T);continue;} 
        //问题转化为在x轴上选出尽量少的点,使所有区间都包含至少一个点}
        for(int i = 1; i <= n; i++)
        {
            double t = sqrt(1.0 * d * d - 1.0 * y[i] * y[i]);
            s[i].l = (double)x[i] - t; s[i].r = (double)x[i] + t;
        }
        sort(s + 1, s + 1 + n, cmp);
        double pos = -inf;//pos记录上一个点的位置
        for(int i = 1; i <= n; i++)
        {
            if(s[i].l > pos)//若两个区间没有交集,点数+1
            {
                ans++;
                pos = s[i].r;
            }
            else if(s[i].r < pos) pos = s[i].r;
        }
        printf("Case %d: %d\n", T, ans);
    }
    return 0;
}
View Code

 

  • 分治

  「LibreOJ β Round #4」游戏

  emmm......读入WA了2次

  难受

  因为X可以填入任意实数,所以填X可以改变逆序对的奇偶,即最后填X的人能直接获胜,判一下X的奇偶即可

  若序列中不存在X,胜负已定,直接计算逆序对个数

  特别地,对于 n = 1 的情况,qmqmqm 必输

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

int n,cnt;
int a[N], t[N];

void mergesort(int l, int r)
{
    if(l == r) {t[l] = a[l]; return;}
    int mid = (l + r) >> 1;
    mergesort(l, mid); mergesort(mid + 1, r);
    int i = l, j = mid + 1, k = l;
    while(i <= mid && j <= r)
    {
        if(a[i] > a[j])
        {
            t[k++] = a[j++];
            cnt += (mid - i + 1) % 2;
        }
        else t[k++] = a[i++];
    }
    while(i <= mid) t[k++] = a[i++];
    while(j <= r) t[k++] = a[j++];
    for(int i = l; i <= r; i++) a[i] = t[i];
}

int main()
{
    scanf("%d", &n);
    if(n == 1) {cout << "L"; return 0;}
    for(int i = 1; i <= n; i++)
    {
        char s[15]; scanf("%s", s);
        if(s[0] == 'X') cnt++;
        else
        {
            int x = 0, f = 1, l = strlen(s);
            for(int j = 0; j < l; j++)
            {
                if(s[j] == '-') f = -1;
                else x = x * 10 + s[j] - '0';
            }
            a[++a[0]] = x * f;
        }
    }
    if(!cnt) mergesort(1, a[0]);
    if(cnt % 2) cout << "W"; else cout << "L";
    return 0;
}
View Code

  ~~~~~

  今天效率还是好低啊

 

4.18

   这两天再水一下dp和数据结构,就得开始学习新东西了

  ~~~~~

  luogu1020 导弹拦截

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;

int a[N], f[N];

int main()
{
    int x; while(scanf("%d", &x) != EOF) {a[++a[0]] = x;}
    for(int i = a[0]; i > 0; i--)
    {
        if(!f[0] || a[i] >= f[f[0]]) f[++f[0]] = a[i];
        else
        {
            int p = upper_bound(f + 1, f + 1 + f[0], a[i]) - f;
            f[p] = a[i];
        }
    }
    printf("%d\n", f[0]); f[0] = 0;
    for(int i = 1; i <= a[0]; i++)
    {
        if(!f[0] || a[i] > f[f[0]]) f[++f[0]] = a[i];
        else
        {
            int p = lower_bound(f + 1, f + 1 + f[0], a[i]) - f;
            f[p] = a[i];
        }
    }
    printf("%d", f[0]);
    return 0;
}
View Code

  

  luogu1880 [NOI1995]石子合并

  mn[i][j]表示合并完区间[i, j]的最小分数

  很容易想到: mn[i][j] = min(mn[i][k] + mn[k + 1][j] + sum(i, j));   (i <= k < j)

  考虑递推顺序,得到mn[i][j]的前提是已经提前算出[i, j]子区间的mn值,枚举 i 或 j 并不是很容易处理

  可以想到枚举区间长度,再用 i 算出 j 值,这样便可以确保所需状态已经求出

  最大值同理

#include <bits/stdc++.h>
using namespace std;
const int N = 205;
const int inf = 1e9;

int n, a[N], sum[N];
int mn[N][N], mx[N][N];//mn[i][j],mx[i][j]分别代表区间[i,j]合并的最 小/大 得分

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {scanf("%d", &a[i]); a[i + n] = a[i];}
    for(int i = 1; i <= 2 * n; i++) sum[i] = sum[i - 1] + a[i];
    for(int l = 1; l <= n; l++)
        for(int i = 1, j = i + l; j < 2 * n; i++, j++)
        {
            mn[i][j] = inf;
            for(int k = i; k < j; k++)
            {
                mn[i][j] = min(mn[i][j], mn[i][k] + mn[k + 1][j] + sum[j] - sum[i - 1]);
                mx[i][j] = max(mx[i][j], mx[i][k] + mx[k + 1][j] + sum[j] - sum[i - 1]);
            }
        }
    int ans[2] = {inf, 0};
    for(int i = 1; i <= n; i++)
    {
        ans[0] = min(ans[0], mn[i][i + n - 1]);
        ans[1] = max(ans[1], mx[i][i + n - 1]);
    }
    cout << ans[0] << endl << ans[1];
    return 0;
}
View Code

 

  luogu1140 相似基因

#include <bits/stdc++.h>
using namespace std;
const int N = 105;
const int inf = 1e9;
const int sim[5][5] = { {5, -1, -2, -1, -3},
                        {-1, 5, -3, -2, -4},
                        {-2, -3, 5, -2, -2},
                        {-1, -2, -2, 5, -1},
                        {-3, -4, -2, -1, 0} };                        

int n, m, a[N], b[N];
int f[N][N];
char s[N];

void get(int l, int T[N])
{
    for(int i = 0; i < l; i++)
    {
        if(s[i] == 'A') T[i + 1] = 0;
        else if(s[i] == 'C') T[i + 1] = 1;
        else if(s[i] == 'G') T[i + 1] = 2;
        else if(s[i] == 'T') T[i + 1] = 3;
    }
}

int main()
{
    scanf("%d%s", &n, s); get(n, a);
    scanf("%d%s", &m, s); get(m, b);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) f[i][j] = -inf;
    for(int i = 1; i <= n; i++) f[i][0] = f[i - 1][0] + sim[a[i]][4];
    for(int i = 1; i <= m; i++) f[0][i] = f[0][i - 1] + sim[b[i]][4];
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            f[i][j] = max(f[i][j], f[i][j - 1] + sim[b[j]][4]);
            f[i][j] = max(f[i][j], f[i - 1][j] + sim[a[i]][4]);
            f[i][j] = max(f[i][j], f[i - 1][j - 1] + sim[a[i]][b[j]]);
        }
            
    cout << f[n][m];
    return 0;
}
View Code

 

  luogu1282 多米诺骨牌

  f[i][j] 表示前 i 个纸牌,上下差值为 j 时的最小翻动次数

  于是就有 f[i][j] = min(f[i - 1][j - (a[i] - b[i])], f[i - 1][j + (a[i] - b[i])])

  注意数组别越界

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;

int n, a[N], b[N];
int f[N][15 * N];

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d%d", &a[i], &b[i]);
    memset(f, 127, sizeof(f)); f[0][0 + 6000] = 0;
    for(int i = 1; i <= n; i++)
        for(int j = -6000; j <= 6000; j++)
        {
            j += 6000;
            f[i][j] = min(f[i - 1][j - a[i] + b[i]], f[i - 1][j - b[i] + a[i]] + 1);
            j -= 6000;
        }
    for(int i = 0; i <= 6000 ; i++)
    {
        int ans = min(f[n][6000 + i], f[n][6000 - i]);
        if(ans <= n) {cout << ans; return 0;}
    }
    return 0;
}
View Code

 

  luogu1508 Likecloud-吃、吃、吃

  从下向上跟从上到下没太大区别

  f[i][j] = max(f[i - 1][j - 1], f[i - 1][j], f[i - 1][j + 1]);

  注意宽为奇数,最后答案就是max(f[n][m / 2 ], f[n][m / 2 + 1], f[n][m / 2 + 2]);

#include <bits/stdc++.h>
using namespace std;
const int N = 205;

int n, m;
int mp[N][N], f[N][N];

int main()
{    
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) scanf("%d", &mp[i][j]);
    memset(f, -11, sizeof(f));
    for(int i = 0; i <= m + 1; i++) f[0][i] = 0;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            f[i][j] = max(f[i - 1][j - 1], f[i - 1][j + 1]);
            f[i][j] = max(f[i][j], f[i - 1][j]);
            f[i][j] += mp[i][j];
        }
    cout << max(f[n][m / 2], max(f[n][m / 2 + 1], f[n][m / 2 + 2]));
    return 0;
}
View Code

 

  ~~~~~

  今天又被jushen鄙视了

  我该如何委婉地提醒他我比他菜很多这一事实?

 

4.19

  昨天的石子合并复杂度是O(n3),四边形不等式优化一下可以达到O(n2)

#include <bits/stdc++.h>
using namespace std;
const int N = 205;
const int inf = 1e9;

int n, a[N], sum[N];
int mn[N][N], mx[N][N];//mn[i][j],mx[i][j]分别代表区间[i,j]合并的最 小/大 得分
int sn[N][N];//sn[i][j]代表区间[i,j]合并得到最小值时的k值

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {scanf("%d", &a[i]); a[i + n] = a[i];}
    for(int i = 1; i <= 2 * n; i++)
    {
        sum[i] = sum[i - 1] + a[i];
        sn[i][i] = i;
    }
    
    for(int l = 1; l <= n; l++)
        for(int i = 1, j = i + l; j < 2 * n; i++, j++)
        {
            mx[i][j] = max(mx[i][j - 1], mx[i + 1][j]) + sum[j] - sum[i - 1];//最大值不满足单调性,不能用四边形不等式,但最大值总是在端点处取到???
            mn[i][j] = inf;
            for(int k = sn[i][j - 1]; k <= sn[i + 1][j]; k++)
                if(mn[i][j] > mn[i][k] + mn[k + 1][j])
                    {mn[i][j] = mn[i][k] + mn[k + 1][j]; sn[i][j] = k;}
            mn[i][j] += sum[j] - sum[i - 1];
        }
    int ans[2] = {inf, 0};
    for(int i = 1; i < n; i++)
    {
        ans[0] = min(ans[0], mn[i][i + n - 1]);
        ans[1] = max(ans[1], mx[i][i + n - 1]);
    }
    cout << ans[0] << endl << ans[1];
    return 0;
}
View Code

  其实还是有一点不太懂,先挖坑吧,以后会填的

 

  luogu1387 最大正方形

#include <bits/stdc++.h>
using namespace std;
const int N = 105;

int n, m, mp[N][N];
int f[N][N];//f[i][j]表示以(i,j)为右下角的正方形边长

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) scanf("%d", &mp[i][j]);
    int ans = 0;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            if(!mp[i][j]) f[i][j] = 0;
            else f[i][j] = min(f[i - 1][j - 1], min(f[i][j - 1], f[i - 1][j])) + 1;
            ans = max(ans, f[i][j]);
        }
    cout << ans;
    return 0;
}
View Code

 

  luogu1417 烹调方案

#include <bits/stdc++.h>
using namespace std;
const int N = 55;
#define ll long long 

int T, n;
ll a[N], b[N], c[N];
ll f[100005];

struct node 
{
    ll a, b, c;
}s[N];

bool cmp(node x, node y)
{
    return x.c * y.b < y.c * x.b;
}

int main()
{
    scanf("%d%d", &T, &n);
    for(int i = 1; i <= n; i++) scanf("%lld", &s[i].a);
    for(int i = 1; i <= n; i++) scanf("%lld", &s[i].b);
    for(int i = 1; i <= n; i++) scanf("%lld", &s[i].c);
    sort(s + 1, s + 1 + n, cmp);
    for(int i = 1; i <= n; i++)//前i件物品
        for(ll j = T; j >= s[i].c; j--)//已经花费的时间
            f[j] = max(f[j], f[j - s[i].c] + s[i].a - j * s[i].b);
    ll ans = 0;
    for(int i = 0; i <= T; i++) ans = max(ans, f[i]);
    cout << ans;
    return 0;
}
View Code

  ~~~~~

  好烦啊,根本看不进去东西

 

4.20

  luogu1736 创意吃鱼法

#include <bits/stdc++.h>
using namespace std;
const int N = 2505;

int n, m, ans;
int l[N][N], r[N][N];
int mp[N][N], f[N][N][2];

int main()
{
    while(scanf("%d%d", &n, &m) != EOF)
    {
        ans = 0;
        memset(l, 0, sizeof(l)); memset(r, 0, sizeof(r));
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
            {
                scanf("%d", &mp[i][j]);
                l[i][j] = l[i][j - 1] + mp[i][j];
                r[i][j] = r[i - 1][j] + mp[i][j];
            }
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
            {
                if(!mp[i][j]) f[i][j][0] = f[i][j][1] = 0;
                else
                {
                    for(int k = f[i - 1][j - 1][0]; k >= 0; k--)//这一层的常数我感觉很小,然而并不会证 
                    {
                        if(r[i][j] - r[i - k - 1][j] != 1) continue;
                        if(l[i][j] - l[i][j - k - 1] != 1) continue;
                        f[i][j][0] = k + 1; break;
                    }
                    for(int k = f[i - 1][j + 1][1]; k >= 0; k--)
                    {
                        if(r[i][j] - r[i - k - 1][j] != 1) continue;
                        if(l[i][j + k] - l[i][j - 1] != 1) continue;
                        f[i][j][1] = k + 1; break;
                    }
                }
                ans = max(ans, max(f[i][j][0], f[i][j][1]));
            }        
        cout << ans << endl;
    }
    return 0;
}
View Code

 

  uoj107【APIO2013】ROBOTS

  

4.24

  又浪了几天......

  难受

  ~~~~~

  bzoj2333: [SCOI2011]棘手的操作

  http://www.cnblogs.com/XYZinc/p/8930911.html

 

4.25

  poj1062 昂贵的聘礼

  dfs

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <cstring>
using namespace std;
const int N = 105;

int m, n;

struct node
{
    int p, l, sz;
    int t[N], v[N];
}s[N];

bool vis[N];
int dfs(int x, int mn, int mx)
{
    int cnt = s[x].p;
    for(int i = 1; i <= s[x].sz; i++)
    {
        int to = s[x].t[i]; if(vis[to]) continue;
        if(abs(mn - s[to].l) <= m && abs(mx - s[to].l) <= m)
        {
            vis[to] = true;
            cnt = min(cnt, dfs(to, min(mn, s[to].l), max(mx, s[to].l)) + s[x].v[i]);
            vis[to] = false;
        }
    }
    return cnt;
}

int main()
{
    scanf("%d%d", &m, &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%d%d", &s[i].p, &s[i].l, &s[i].sz);
        for(int j = 1; j <= s[i].sz; j++) scanf("%d%d", &s[i].t[j], &s[i].v[j]);
    }
    vis[1] = true;
    cout << dfs(1, s[1].l, s[1].l);
    return 0;
}
View Code

 

  poj1797 Heavy Transportation

  kruskal 

  唉,注意输出格式

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1005;
const int M = 1000005;

int T, n, m, fa[N];

struct node{int x, y, w;}s[M];

bool cmp(node a, node b) {return a.w > b.w;}

int findf(int x)
{
    if(fa[x] == x) return x;
    return fa[x] = findf(fa[x]);
}

void merge(int x, int y)
{
    x = findf(x); y = findf(y);
    if(x != y) fa[x] = y;
}

int main()
{
    scanf("%d", &T);
    for(int id = 1; id <= T; id++)
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; i++) scanf("%d%d%d", &s[i].x, &s[i].y, &s[i].w);
        sort(s + 1, s + 1 + m, cmp);
        for(int i = 1; i <= n; i++) fa[i] = i;
        for(int i = 1; i <= m; i++)
        {
            merge(s[i].x, s[i].y);
            if(findf(1) == findf(n))
            {
                printf("Scenario #%d:\n", id);
                printf("%d\n", s[i].w);
                if (id != T) printf("\n");
                break;
            }
        }
    }
    return 0;
}
View Code

 

4.26

  就水了场比赛

 

4.27

  poj3352 Road Construction

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1005;

char s[30];
int n, m, ans, deg[N];
vector<int> to[N];

int t, dfn[N], low[N]; bool flag[N];
void tarjan(int x, int fa)
{
    dfn[x] = low[x] = ++t; flag[x] = true;
    for(int i = 0; i < to[x].size(); i++)
    {
        int k = to[x][i];
        if(k == fa) continue;
        if(!dfn[k])
        {
            tarjan(k, x);
            low[x] = min(low[x], low[k]);
        }
        else if(flag[k]) low[x] = min(low[x], dfn[k]);
    }
}

void clear()
{
    for(int i = 1; i <= n; i++) to[i].clear();
    memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn));
    memset(flag, 0, sizeof(flag)); memset(deg, 0, sizeof(deg));
    
}

int main()
{
    while(scanf("%d%d", &n, &m) != EOF)
    {
        clear();
        for(int i = 1; i <= m; i++)
        {
            int x, y; scanf("%d%d", &x, &y);
            to[x].push_back(y); to[y].push_back(x);
        }
        tarjan(1, 0);
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j < to[i].size(); j++)
            {
                int k = to[i][j];
                if(low[i] != low[k]) deg[low[i]]++;
            }
        }
        for(int i = 1; i <= n; i++) if(deg[i] == 1) ans++;
        cout << (ans + 1) / 2 << endl;
    }
    return 0;
}
View Code

 

  poj1112 Team Them Up!

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 105;

int n, col[N], sum[3];
int a[N][N], b[N][N], num;
bool mp[N][N], f[N], dp[N][N * 2], id[N][N * 2], fail;

void dfs(int x, int c)
{
    col[x] = c;
    if(c == 1) a[num][++sum[1]] = x;
    else b[num][++sum[2]] = x;
    for(int y = 1; y <= n; y++)
    {
        if(mp[x][y])
        {
            if(col[y])
            {
                if(col[y] != 3 - c) {fail = true; return;}
            }
            else dfs(y, 3 - c);
        }
        if(fail) return;
    }
}

int pos;
vector<int> ans[2];
void print(int i, int dif)
{
    if(!i) return;
    if(!id[i][dif])
    {
        for(int k = 1; k <= a[i][0]; k++) ans[0].push_back(a[i][k]);
        for(int k = 1; k <= b[i][0]; k++) ans[1].push_back(b[i][k]);
        print(i - 1, dif - a[i][0] + b[i][0]);
    }
    else
    {
        for(int k = 1; k <= a[i][0]; k++) ans[1].push_back(a[i][k]);
        for(int k = 1; k <= b[i][0]; k++) ans[0].push_back(b[i][k]);
        print(i - 1, dif + a[i][0] - b[i][0]);
    }
    
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        int x; 
        while(scanf("%d", &x) && x) f[x] = 1;
        for(int j = 1; j <= n; j++)
            if(!f[j] && i != j) mp[i][j] = mp[j][i] = true;
        memset(f, 0, sizeof(f));
    }
    for(int i = 1; i <= n; i++)
        if(!col[i])
        {
            sum[1] = sum[2] = 0; num++;
            dfs(i, 1);
            if(fail) {cout << "No solution"; return 0;}
            a[num][0] = sum[1]; b[num][0] = sum[2];
        }
    dp[0][n] = true;
    for(int i = 0; i < num; i++)
    {
        int x = a[i + 1][0] - b[i + 1][0];
        for(int j = -n; j <= n; j++)
            {
                if(!dp[i][j + n]) continue;
                dp[i + 1][j + x + n] = true;
                id[i + 1][j + x + n] = 0;
                dp[i + 1][j - x + n] = true;
                id[i + 1][j - x + n] = 1;
            }
    }
    for(int i = 0; i <= n; i++)
        if(dp[num][n + i]) {pos = i; break;} else if(dp[num][n - i]) {pos = -i; break;}
    print(num, n + pos);
    sort(ans[0].begin(), ans[0].end()); sort(ans[1].begin(), ans[1].end());
    cout << ans[0].size();
    for(int i = 0; i < ans[0].size(); i++) cout << " " << ans[0][i]; cout << endl;
    cout << ans[1].size();
    for(int i = 0; i < ans[1].size(); i++) cout << " " << ans[1][i];
    return 0;
}
View Code

 

4.28

  打了一下fft的板子

  ~~~~~

  被抓去中午给萌新讲动态规划。。。

  我其实很菜的啊。。。

  先预习一波吧。。。

 

4.29

  kd-tree 

 

5.3

   poj3237 Tree

  树链剖分,边权转化为点权

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 100005;
const int M = N * 2;
const int inf = 1e9;

inline int read()
{
    int x = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-') f  = -1; ch = getchar();}
    while(isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}

struct edge
{
    int fr, to, w;
}E[N];

struct node
{
    int l, r, f, mn, mx;
    node(){}
    node(int ll, int rr, int ff, int nn, int xx) {l = ll; r = rr; f = ff; mn = nn; mx = xx;}
}T[N << 3];

int num, to[M], w[M], nt[M], pt[N];
void add(int x, int y, int v) {to[++num] = y; w[num] = v; nt[num] = pt[x]; pt[x] = num;}

int n, sz[N], fa[N], deep[N], son[N];
void dfs1(int x)
{
    sz[x] = 1;
    for(int e = pt[x]; e; e = nt[e])
    {
        int k = to[e];
        if(k == fa[x]) continue;
        fa[k] = x;
        deep[k] = deep[x] + 1;
        dfs1(k);
        sz[x] += sz[k];
        if(sz[k] > sz[son[x]]) son[x] = k;
    }
}

int t, dfn[N], top[N];
void dfs2(int x, int tp)
{
    top[x] = tp; dfn[x] = ++t;
    if(!son[x]) return;
    dfs2(son[x], tp);
    for(int e = pt[x]; e; e = nt[e])
        if(to[e] != son[x] && to[e] != fa[x]) dfs2(to[e], to[e]);
}

void build(int p, int x, int y)
{
    T[p] = node(x, y, 0, inf, -inf);
    if(x == y) return;
    int mid = (x + y) >> 1;
    build(p << 1, x, mid); build(p << 1 | 1, mid + 1, y);
}

void neg(int p)
{
    T[p].mn *= -1; T[p].mx *= -1;
    swap(T[p].mn, T[p].mx);
}

void pushup(int p)
{
    T[p].mn = min(T[p << 1].mn, T[p << 1 | 1].mn);
    T[p].mx = max(T[p << 1].mx, T[p << 1 | 1].mx);
}

void pushdown(int p)
{
    if(T[p].l == T[p].r || !T[p].f) return;
    T[p << 1].f ^= 1; T[p << 1 | 1].f ^= 1;
    neg(p << 1); neg(p << 1 | 1);
    T[p].f = 0;
}

void update(int p, int x, int y, int v)
{
    pushdown(p);
    int pl = T[p].l, pr = T[p].r;
    if(pl == x && pr == y)
    {
        if(v == inf) {T[p].f = 1; neg(p);}
        else T[p].mn = T[p].mx = v;
        return;
    }
    int mid = (pl + pr) >> 1; 
    if(y <= mid) update(p << 1, x, y, v);
    else if(x > mid) update(p << 1 | 1, x, y, v);
    else {update(p << 1, x, mid, v); update(p << 1 | 1, mid + 1, y, v);}
    pushup(p);
}

void Update(int x, int y, int v)
{
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        update(1, dfn[top[x]], dfn[x], v);
        x = fa[top[x]];
    }
    if(x == y) return;
    if(deep[x] < deep[y]) swap(x, y);
    update(1, dfn[y] + 1, dfn[x], v);
}

int query(int p, int x, int y)
{
    pushdown(p);
    int pl = T[p].l, pr = T[p].r;
    if(pl == x && pr == y) return T[p].mx;
    int mid = (pl + pr) >> 1;
    if(y <= mid) return query(p << 1, x, y);
    else if(x > mid) return query(p << 1 | 1, x, y);
    else return max(query(p << 1, x, mid), query(p << 1 | 1, mid + 1, y));
}

int Query(int x, int y)
{
    int cnt = -inf;
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        cnt = max(cnt, query(1, dfn[top[x]], dfn[x]));
        x = fa[top[x]];
    }
    if(x == y) return cnt;
    if(deep[x] < deep[y]) swap(x, y);
    cnt = max(cnt, query(1, dfn[y] + 1, dfn[x]));
    return cnt;
}

void clear()
{
    num = t = 0;
    memset(to, 0, sizeof(to)); memset(w, 0, sizeof(w));
    memset(nt, 0, sizeof(nt)); memset(pt, 0, sizeof(pt));
    memset(deep, 0, sizeof(deep)); memset(son, 0, sizeof(son));
    memset(fa, 0, sizeof(fa)); memset(sz, 0, sizeof(sz));
}

int main()
{
    int op = read();
    while(op--)
    {
        clear();
        n = read();
        for(int i = 1; i < n; i++)
        {
            E[i].fr = read(); E[i].to = read(); E[i].w = read();
            add(E[i].fr, E[i].to, E[i].w); add(E[i].to, E[i].fr, E[i].w);
        }
        dfs1(1);
        dfs2(1, 1);
        build(1, 1, t);
        for(int i = 1; i < n; i++)
        {
            if(deep[E[i].fr] > deep[E[i].to]) swap(E[i].fr, E[i].to);
            update(1, dfn[E[i].to], dfn[E[i].to], E[i].w);
        }
        while(true)
        {
            char s[10]; scanf("%s", s);
            if(s[0] == 'C')
            {
                int id = read(), v = read();
                update(1, dfn[E[id].to], dfn[E[id].to], v);
            }
            else if(s[0] == 'N')
            {
                int x = read(), y = read();
                Update(x, y, inf);
            }
            else if(s[0] == 'Q')
            {
                int x = read(), y = read();
                printf("%d\n", Query(x, y));
            }
            else break;
        }
    }
    return 0;
}
View Code

 

5.4

  poj3694 Network

  tarjan

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath> 
#include <vector>
using namespace std; 
const int N = 200005;

inline int read()
{
    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;
}

int n, m, cas, Q, ans;
vector<int> to[N];

int t, dfn[N], low[N], fa[N], deep[N]; bool flag[N], br[N];
void tarjan(int x)
{
    dfn[x] = low[x] = ++t; flag[x] = true;
    for(int i = 0; i < to[x].size(); i++)
    {
        int k = to[x][i];
        if(!dfn[k])
        {
            fa[k] = x;
            deep[k] = deep[x] + 1;
            tarjan(k);
            low[x] = min(low[x], low[k]);
            if(dfn[x] < low[k]) ans++, br[k] = true;//br[i]记录i与fa[i]的连边是否为桥
        }
        else if(k != fa[x])low[x] = min(low[x], dfn[k]);
    }
}

void lca(int x, int y)
{
    if(deep[x] < deep[y]) swap(x, y);
    while(deep[x] > deep[y])
    {
        if(br[x]) {ans--; br[x] = false;}
        x = fa[x];
    }
    while(x != y)
    {
        if(br[x]) {ans--; br[x] = false;}
        if(br[y]) {ans--; br[y] = false;}
        x = fa[x]; y = fa[y];
    }
}

void clear()
{
    ans = t = 0;
    for(int i = 1; i <= n; i++) to[i].clear();
    memset(flag, 0, sizeof(flag)); memset(br, 0, sizeof(br));
    memset(deep, 0, sizeof(deep)); memset(fa, 0, sizeof(fa));
    memset(dfn, 0, sizeof(dfn));
}

int main()
{
    n = read(); m = read();
    while(n + m)
    {
        clear();
        printf("Case %d:\n", ++cas);
        for(int i = 1; i <= m; i++)
        {
            int x = read(), y = read();
            to[x].push_back(y); to[y].push_back(x);
        }
        tarjan(1);
        Q = read();
        while(Q--)
        {
            int x = read(), y = read();
            lca(x, y);
            printf("%d\n", ans);
        }
        printf("\n");
        n = read(); m = read();
    }
    return 0;
}
View Code

 

5.5

  又水了一天

 

 

5.10 - 5.14

  丝滑拿铁

  除了意识到自己到底多菜,什么收获也没有

 

5.15

  早上做了一下 NOI2014 DAY1

  接下来的时间打算就这样,早上做题感受一下自己多菜,下午改题,晚上学点新东西

  也不打算学什么太难的东西了,学了也打不出来

  emmm......

  难受

 

5.18 - 5.28

  考试

 

5.28

  两边都没过,没学上了啊

  这段时间真的是完全荒废了,什么都没学,考试的题也没改

  怕是要痛改前非,重新做人啊

 

5.29

  • 分治

  luogu1257

  luogu1429(优美一点的分治,或者旋转坐标轴乱搞)

  • 矩阵快速幂

  luogu1962

  luogu3758

 

6.12

  • 树的直径

  bzoj2282

 

6.13

  • 树的直径

  luogu3761

 

6.15

  bzoj1036 [ZJOI2008]树的统计Count

 

  luogu1072 Hankson 的趣味题

  gcd && lcm

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

int gcd(int a, int b)
{
    if(!b) return a;
    return gcd(b, a % b);
}

int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        int a[2], b[2]; scanf("%d%d%d%d", &a[0], &a[1], &b[0], &b[1]);
        int k = a[0] / a[1], t = b[1] / b[0], ans = 0;
        for(int x = 1; x * x <= b[1]; x++)
        {
            if(b[1] % x != 0) continue;
            if(x % a[1] == 0 && gcd(x / a[1], k) == 1 && gcd(t, b[1] / x) == 1) ans++;
            int y = b[1] / x;
            if(x == y) continue;
            if(y % a[1] == 0 && gcd(y / a[1], k) == 1 && gcd(t, b[1] / y) == 1) ans++;
        }
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

posted @ 2018-04-11 13:21  XYZinc  阅读(376)  评论(8编辑  收藏  举报