7月、8月考试总结(1)

7.10: Test1 惨遭爆零 TAT

   第一题 在本地测是过了的  到了教师机莫名输出0 ??   一道spfa的板子题  还做过 WA了也就GG。。[POJ2502]Subway

   后来发现了  结构体强转有大问题????  woc

   第二题 听大佬讲 有三种方法

  1是floyd判一下 f[x][y] ?= f[x][k] + f[k][y] 还标记个flag(是否存在); 

  2是一个spfa找负环 这需要建一个神奇的图;

  3是一个诡异的贪心  (左端相等 减去左边相等的数 再加入优先队列 如果区间相等 判断数是否相等 不相等就false)。

  反正我都没想到  (难道高斯消元+区间离散 不能做?? 到时候再研究)洛谷【P2294】[HNOI2005]狡猾的商人 

     后来点开标签看了看 原来是差分约束(虽然原来好像讲过,但根本不记得了) 去网上找了篇好博文 终于懂了

   第三题 一道强联通分量缩点 + 树形(DAG)dp  没时间写了 也只好GG    洛谷【P3436】[POI2006]PRO-Professor Szu

   总结:先做思路更明显的题  程序注意细节  不要瞎搞  再接再厉 明天继续 fighting


 

7.12:Test2 130分。。(一般人拿的分qwq)

  第一题 一道求解涂色方案数问题 判是否可行 看到就一脸懵 以为又是一道数学找规律题 草草地打完了爆搜就没去动了 后来回头想来写dp没写出来QAQ

  正解是矩阵快速幂(膜一波hy大大   构造一个可行型矩阵,乘自己n-1次(用快速幂做),最后再乘上dp矩阵) 还有种神奇方法 倍增思想来做dp  两种时间复杂度差不多都是O(log n)

  第二题 一道trie的裸题,但是数据卡trie,我就竟然奇迹般地写出了hash(似乎还是正解) 竟然时间效率还不错。以后要多多练练hash。 [HDU1075]What are you talking about?

      第三题  一道拓欧的题,不知道拓欧咋写,又咋去用。。。 反正不太会QAQ。。 后来听了几位大牛的讲解  终于搞懂了qwq。。 [POJ2155]C Looooops

  总结:有时候脑洞还是要开大一点 有可能灵机一闪的思路是正解


 

7.13:Test3 200分 (数据太水了。。。正解基本没过。。暴力还有a+b都能AC TAT)

  第一题 一道平面几何题 计算任意两点之间距离的最大值 暴力全部秒过= = 正解是先做一遍凸包 把凸包上的点保留 再做一遍暴枚[POJ2187]Beauty Contest  

  第二题 一道求最大团的题(一开始不知道 写了个点枚暴力复杂度O(n^2 * 2^n)特别高QAQ)后来才知道是一道NP难问题(NPC)GG第一次碰   可以用Bron–Kerbosch算法(但好像会TLE)其实根据这道题的特殊性

  可以把原图延伸为一个补图(将所有原图原本存在的边删掉加上不存在的边)然后跑一边二分图最大匹配 这样就可以把原图中互相不认识的一些点删掉 最后答案就是nl+nr-res [POJ3692]Kindergarten      

  第三题  一道搜索剪枝的题 (考试时候剪枝剪多了WA了 TAT) 有一个玄学剪枝 就是(maxv - sumv) / r * 2 + sums >= ans 这个就将体积换成侧面积来计算接下来的最大面积 这个似乎优化很多

       一开始改了很久 发现枚举高度时 不能直接从h-1开始 有时要从(maxv-sumv-minv[deep-1]) / (i*i)(可用体积除以半径)开始 就是两个的最小值   [POJ1190]生日蛋糕

 


 

7.14:Test4 170分 (这次比较正常。。发挥刚好。)

  第一题 一道最长不上升和不下降的裸题 不能用O(n^2)的算法来做 (n=100000) 要用 二分当前最优解的方法去写。 有点类似于合唱队型。。洛谷【P1091】合唱队形

  第二题 一道特殊的01背包 考试没看出来(因为是乘积)最后只好写了一个DFS 去搜索 结果挂了 只有20分TAT  其实就是按减少饥饿值从大到小排序 如果当前减少饥饿值为负数 就不算 否则就更新f[i](i表示减少饥饿值为i时 最大的战斗力) 最后线性扫一遍就行了 [POJ2184]Cow Exhibition

        第三题  又是一道报复社会的数论题。。 就是筛素数  要用上一种特殊的筛法 Miller-Rabin   这个就需要一些数论基础了  而且为了防爆范围 需要取模乘(类似于快速幂) 而且还需要一个快速幂来计算   这个运用了费马小定理 还有 二次探测定理  [POJ1811]Prime Test


 

7.18:Test5 50分 (TAT倒数第四(还有小朋友) 要被丢出去了)

  第一题 一道搜索贪心 或者 递推dp  太自信了 5min打完就做后面了 没认真看看TAT

  第二题 一道神奇的贪心 将根节点能选的最多节点数计算出来(sum) 再计算出从大到小sum个数的和再加起来。。。没想出来TAT

  第三题  这道题就也是报复社会了。。。暴力打挂了,flag前面特判错了QAQ。。。正解用线段树进行维护 十分复杂(可以媲美工业题了)  

   总结:真的要注重细节啊!!!!!  明天NOI同步赛了。。  争取拿分 沉下心来 好好弄!!!


 

8.2:Test6 120分 (成功诠释暴力骗分的正确方法2333)  PS:以后开始附代码了(还有他们的解题报告。。)  

  第一题 一道神奇的图论题(我考试时并没有理解题目的真正含义,靠暴力三重循环竟然骗了40分0.0)正解是类似于DAG dp,就是计算每一个点能到达的节点个数,因为能到达的节点必须要扩充边。需要用bitset来维护这个集合,可以进行数位优化,除以一个ω。为了防止爆空间,所以跑两遍。。(dy的程序是真的强,十分精炼……)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <bitset>
 7 using namespace std;
 8 #define For(i, l, r) for(int i = (l), _end_ = (int)(r); i <= _end_; ++i)
 9 #define Fordown(i, r, l) for(int i =(r),_end_ = (int)(l); i >= _end_; --i)
10 #define Set(a, v) memset(a, v, sizeof(a))
11 
12 inline int read() {
13     int x = 0, fh = 1; char ch;
14     for(; !isdigit(ch); ch = getchar()) if(ch == '-') fh = -1;
15     for(; isdigit(ch); ch = getchar()) x =(x<<1) + (x<<3) + (ch ^ '0');
16     return x * fh;
17 }
18 
19 const int N = 60100, M = 100100;
20 int to[M], Next[M], Head[N], e = 0;
21 void add_edge (int u, int v) {
22     to[++e] = v;
23     Next[e] = Head[u];
24     Head[u] = e;
25 }
26 
27 bitset<N/2> G[N];
28 bool vis[N];
29 int n, m, ans = 0;
30 void dfs (int u, bool flag) {
31     if (vis[u]) return;
32     vis[u] = true;
33     if (flag && u <= (n>>1) ) G[u][u] = true;
34     else if (!flag && u > (n>>1) ) G[u][u - (n>>1)] = true;
35     for (int i = Head[u]; i; i = Next[i]) {
36         int v = to[i];
37         dfs (v, flag);
38         G[u] |= G[v];
39     }
40     ans += G[u].count();
41 }
42 
43 int main(){
44     freopen ("worldline.in", "r", stdin);
45     freopen ("worldline.out", "w", stdout);
46     n = read(); m = read();
47     For (i, 1, m) {
48         int u = read(), v = read();
49         add_edge (u, v);
50     }
51     For (i, 1, n) dfs (i, true);
52     Set(vis, false);
53     For (i, 1, n) G[i].reset();
54     For (i, 1, n) dfs (i, false);
55     printf ("%d\n", ans - n - m);
56     return 0;
57 }
View Code

  第二题 一道看起来是道网络流,其实是一道贪心的题目0.0(题目把我们带走远了,dy出题真的强……)就是将左节点排序,然后去从左至右,一个个贪心去比较,维护序列用map或者set……(不得不说dy的STL也用的出神入化,不愧是进队爷……QAQ)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define For(i, l, r) for(int i = (l), _end_ = (int)(r); i <= _end_; ++i)
#define Fordown(i, r, l) for(int i =(r),_end_ = (int)(l); i >= _end_; --i)
#define Set(a, v) memset(a, v, sizeof(a))

inline int read() {
    int x = 0, fh = 1; char ch;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') fh = -1;
    for(; isdigit(ch); ch = getchar()) x =(x<<1) + (x<<3) + (ch ^ '0');
    return x * fh;
}

const int N = 100100;
struct node {
    int l, r, s;
    bool operator < (const node &rhs) const {
        return l < rhs.l;
    }
};
node a[N], b[N];
int n, m;
typedef long long ll;
#include <map>
map<int, ll> M;

void solve() {
    int j = 1;
    For (i, 1, n) {
        for(;j <= m && b[j].l <= a[i].l; ++j) 
            if (!M.count(b[j].r) ) M[b[j].r] = b[j].s; 
            else M[b[j].r] += b[j].s;
        while (a[i].s) {
            map<int, ll>::iterator p = M.lower_bound(a[i].r);
            if (p == M.end() ) {puts("No"); return;}
            if (a[i].s < p -> second) {p -> second -= a[i].s; a[i].s = 0;}
            else {a[i].s -= p -> second; p -> second = 0; M.erase(p);}
            }
        }
    puts("Yes"); 
    return; 
}

int main(){
    int t = read();
    while (t--) {
        M.clear();
        n = read(); m = read();
        For (i, 1, n) 
            a[i] = (node) {read(), read(), read()};
        
        For (i, 1, m) 
            b[i] = (node) {read(), read(), read()};
        
        sort (a + 1, a + 1 + n);
        sort (b + 1, b + 1 + m);
        solve();
    }
    return 0;
}
View Code

  第三题 一道题面看了很久看懂,只会打杨辉三角暴力的,恐怖数论题……正解根本看不懂啊QAQ 数论还是太弱了……


 

8.3:Test7 110分(再次成功诠释暴力出奇迹的神奇方法2333)

  第一题 一道概率题 原来从来都不会概率……被逼无奈 写了O(2^n)的暴力来推算……60分的概率dp O(n^2) 也有点难度,也不会QAQ……正解是O(n)的递推……要将递增的每一项对最后期望值的贡献求出来,最后还要将k对它的影响给表示出来……反正很变态= =

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000000 + 10;

int n, k;
double P[maxn];
double p, x, x2, y, ans;

int main() {

    scanf("%d%d", &n, &k);
    for(int i = 0; i < n; i++) {
        scanf("%lf", &p); P[i] = p;

        ans += p * (3 * x2 + 3 * x + 1);
        x2 = p * (x2 + 2 * x + 1);
        x = p * (x + 1);

        ans -= (1.0-p) * (2 * y + 1);
        y = (1.0-p) * (y + 1);
    }

    ans += k * P[0] * P[n-1];
    ans -= k * (1-P[0]) * (1-P[n-1]);

    printf("%lf\n", ans);
    return 0;
}
View Code

  第二题 一道看起来就不会做的题(事实上还是不会做),乘法逆元加上一个区间的变换……反正都不知道……TAT  只挂个正解的代码在上面吧

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

const int maxn = 500 + 5;
const int mod = 998244353;

int n, m;
int a[maxn], d[maxn];

LL S[maxn][maxn];
LL dp[2][maxn][maxn], chs[maxn];

#define ADD(a, b) ((a += b) >= mod ? a -= mod : a)
#define NONE(i, j) (chs[i-1] + chs[n-j] + chs[j-i+1])

LL fpm(LL base, LL exp) {
    LL ans = 1;
    for(; exp > 0; exp >>= 1) {
        if(exp & 1) 
            ans = ans * base % mod;
        base = base * base % mod;
    }
    return ans;
}

void calc(int l, int r, int pos) {

    bool cur = 1;
    for(int i = l; i <= r; ++i)
        for(int j = i; j <= r; ++j) dp[0][i][j] = 0;

    dp[0][l][r] = 1;
    static LL sum = 0;

    for(int t = 0; t < m; ++t) {
        LL (*now)[maxn] = dp[cur], (*lst)[maxn] = dp[cur^1];

        for(int i = l; i <= r; ++i)
            for(int j = i; j <= r; ++j) 
                now[i][j] = lst[i][j] * NONE(i, j);

        for(int i = l; i <= r; ++i) {
            sum = 0;
            for(int j = r; j >= i; --j) {
                now[i][j] = (now[i][j] + sum);
                sum = (sum + lst[i][j] * (n-j));
            }
        }
        for(int j = r; j >= l; --j) {
            sum = 0;
            for(int i = l; i <= j; ++i) {
                now[i][j] = (now[i][j] + sum) % mod;
                sum = (sum + lst[i][j] * (i-1));
            }
        }cur ^= 1;
    }

    for(int i = l; i <= r; ++i)
        for(int j = i; j <= r; ++j) {
            ADD(S[i][pos], dp[cur^1][i][j]);
            ADD(S[j+1][pos], mod-dp[cur^1][i][j]);
        }
}
int main() {
    freopen("B.in", "r", stdin);
    freopen("B.out", "w", stdout);

    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) chs[i] = i * (i+1) >> 1;
    for(int i = 1; i <= n; ++i) scanf("%d", a + i), d[i] = a[i];

    sort(d + 1, d + n + 1);
    for(int i = 1; i <= n; ++i) {
        int l = i, r = i;
        while(l > 1 && a[l-1] <= a[i]) --l;
        while(r < n && a[r+1] <= a[i]) ++r;
        calc(l, r, lower_bound(d + 1, d + n + 1, a[i]) - d);
    }
    
    for(int i = 1; i <= n; i++) 
        for(int j = 1; j <= n; j++) { ADD(S[i][j], S[i-1][j]); }

    LL INV = fpm(n * (n + 1) >> 1, LL (mod - 2) * m);
    for(int i = 1; i <= n; ++i) {
        LL ans = 0, tmp = 0;
        for(int j = 1; j <= n; ++j) if(S[i][j]) {
            ans = (ans + (S[i][j] - tmp) * d[j]) % mod;
            tmp = S[i][j];
        }
        ans = ans * INV % mod;
        printf("%lld\n", (ans + mod) % mod);
    }
    return 0;
}
View Code

  第三题 一道我用暴力骗了90分的题目(Wearry良心出题人QwQ)

正解是先求出dfs序,再用背包在上面跑,标程有些细节还是没看懂……引用wt大佬的博客算了……

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

void chkmax(int & a, int b) { if(a < b) a = b; }

const int oo = 0x3f3f3f3f;
const int maxn = 5000 + 10;
const int maxm = 10000 + 10;

int st[maxn], nxt[maxm], to[maxm], e = 1;
void addedge(int u, int v) {
    to[++e] = v; nxt[e] = st[u]; st[u] = e;
    to[++e] = u; nxt[e] = st[v]; st[v] = e;
}

int dp[maxn][maxn]; //这个dp的第一维下标是更新后的dfs序 
int n, m, dfs_clock;
int dfn[maxn], efn[maxn];
int id[maxn], p[maxn], d[maxn];

void dfs(int u, int f = 0) {
    id[dfn[u] = ++ dfs_clock] = u;
    for(int i = st[u]; i; i = nxt[i]) 
        if(to[i] != f) dfs(to[i], u);
    efn[u] = dfs_clock + 1; //记录u节点能到的最远的儿子编号+1 即选这个节点的祖先节点 能选到的下一个点 
}

int main() {
    freopen("C.in", "r", stdin);
    freopen("C.out", "w", stdout);

    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) scanf("%d%d", d + i, p + i);
    for(int i = 1; i < n; ++i) {
        static int u, v;
        scanf("%d%d", &u, &v);
        addedge(u, v);
    }

    dfs(1);

    memset(dp, ~oo, sizeof dp);
    dp[1][0] = 0; //根节点不取时默认为0 

    int ans = 0;
    for(int i = 1; i <= n; ++i) {
        int u = id[i];
        for(int j = 0; j <= m; ++j) if(dp[i][j] >= -oo) { //负无穷更新其他的毫无意义…… 
            chkmax(ans, dp[i][j]); //更新当前答案的最大值 
            chkmax(dp[efn[u]][j], dp[i][j]);  //更新
            if(j + p[u] <= m) //如果还在容量之内 
                chkmax(dp[i+1][j + p[u]], dp[i][j] + d[u]); //更新下一个(儿子或者efn)的背包 
        }
    }
    for(int i = 0; i <= m; ++i) chkmax(ans, dp[n+1][i]);
    printf("%d\n", ans);
    
    return 0;
}
View Code

 8.3:Test8 5分(这个分数太恐怖了……题目有些BT……但我的暴力也没打好,细节没注意QAQ)

  第一题 一道二分答案加堆维护的题目……细节比较多……需要有些神奇思路,以及一些方法处理

  第二题 一道贼难的数论题……好不容易推出了暴力,结果还打错了TAT 正解运用的定理,我一个都不懂,以后要恶补数论了啊!!

  第三题 一道坑比的生成树题目……TAT 第一个点开始就要long long了  结果最大值开小了 GG了 正解也不懂 一个01 trie有些变态…… 20%的快速幂也没混到,贪了,数组小了TAT

  30分解法见大佬博客2333 hzwer


 

 

posted @ 2017-07-10 21:12  zjp_shadow  阅读(358)  评论(3编辑  收藏  举报