zoukankan      html  css  js  c++  java
  • 18.8.17 考试总结

    高斯消元
    【问题描述】
    everlasting 觉得太无聊了,于是决定自己玩游戏!

    他拿出了n 个小圆,第i 个的颜色是ai。接着他将这n 个小圆复制m 次并依次连接起来。

    之后他发现其中有很多颜色相同的小圆,于是他决定:每有k 个连续颜色相同的小圆就将他们消去,

    并将剩下的依次连接。(注意只会消除k个,即使有超过k 个)他将每次从头开始不断进行这个操作直到无法操作为止。

    他想知道最后能剩下多少个小圆?


    【输入格式】

    从文件guass.in 中输入数据。

    第一行三个正整数n,m,k,表示开始小圆的个数,复制次数和消除连续小圆
    的个数。
    第二行n 个正整数,第i 个数表示第i 个小圆的颜色。

     

    【输出格式】

    输出到文件guass.out 中。

    一个整数,表示剩余小圆的个数。

     

    这道题毫无算法可言.. 就是极端恶星的模拟模拟模拟 然后细节暴多 机房里面只有turuisen大佬花了三个小时搞出来了

    然后就是lantx花了两个小时真 乱搞弄了95

    我? 我一个样例都没过的错误程序还狗了40分...受宠若惊了

    先把在一个循环里的连续k个相同都去掉,然后算出头和尾能消去的个数

    ,然后就是每个循环剩余长度*(m-1)+仅去掉同一循环的剩余数的个数。

    为什么呢 画个图就清楚了

     

    每个循环剩余长度就是天蓝色设为x 最后消去之后还剩下m * x 但是两头的湖蓝色并没有消去

    湖蓝色长度和就为一整块长度 - x 所以总共长度就是一整块长度 + (m - 1) * x

    但是可能他搞完之后中间的天蓝色凑到一起也可以被消去 特判一下就好了

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N = 1e6 + 5;
    int x,s[N][2],n,m,p,cnt,tot;
    ll ans;
    
    int main( ) {
        
        freopen("guass.in","r",stdin);
        freopen("guass.out","w",stdout);
        scanf("%d%d%d",& n,& m,& p);
        for(int i = 1;i <= n;i ++) {
            scanf("%d",& x);
            if(! cnt || s[cnt][0] != x) {
                s[++ cnt][0] = x;
                s[cnt][1] = 1;
            }
            else s[cnt][1] ++;
            if(s[cnt][1] == p) s[cnt][1] = 0,cnt --;
        }    
        for(int i = 1;i <= cnt;i ++) tot += s[i][1];
        int head = 1,tail = cnt;
        while(head < tail && s[head][0] == s[tail][0]) {
            if((s[head][1] + s[tail][1]) % p == 0) head ++,tail --;
            else {
                s[head][1] = (s[head][1] + s[tail][1]) % p;
                s[tail][1] = 0;
                break;
            }
        }
        if(head < tail) {
            for(int i = head;i <= tail;i ++) ans += (ll)s[i][1];
            ans = (ll)tot + 1LL * (m - 1) * ans; 
        }
        else {
            if(s[head][1] * m % p == 0) ans = 0;
            else {
                ans = (ll)s[head][1];
                ans = (ll)tot + (ll)ans * (m - 1);
                ans -= 1LL * s[head][1] * m - 1LL * s[head][1] * m % p;
            }
        }
        printf("%I64d",ans);
    }

    糖果镇
    【问题描述】
    yyc 来到了糖果镇,她在这里能得到好多好吃的棒棒糖^_^,糖果镇的道路是一个n*m方阵,

    在每个点上会有一些糖果,但是yyc每到一个点都会拿走所有的糖果,并且她只能向下走或者向右走,

    且要从起点(1,1)走到终点(n,m),否则她会被留在糖果镇贪婪的恶魔吃掉⊙o⊙

    当然,为了不让一个人占有过多的棒棒糖,糖果镇决定让每一个人最后得到的糖果数对于p取模。

    所以现在yyc想请你帮她算一算这样她最多能得到多少的棒棒糖。


    【输入格式】
    从文件candy.in中输入数据。

    第一行3个正整数n,m,p

    接下来m行,每行n个数,第i行第j列a[i][j]表示该点的糖果数。


    【输出格式】
    输出到文件candy.out中。

    一行,一个整数,表示答案。

     

    当m<=2时,枚举分界点,预处理前缀和就好了

    对于另外20%,直接dp[i][j]表示到点i,j的最优答案

    对于100%,我们可以枚举第二次下行的分界点,然后我们可以统计出第一次下行的影响,

    就是第一行到x的前缀和减去第二行到x-1的前缀和,第二行就是到枚举端点的前缀和,

    这样在已知第二次下行的分界点时,第二行和第三行的贡献是已知的,

    我们只要找到模意义下第一行的最优贡献就好了,这个就可以用set维护,找前驱。

    (如果是枚举第一行的分界点那就是倒着搞 这样子就能保证我能用的存了 不能用的没存)

    第一次用set感觉好高级啊 z大爷tql...!!!!

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N = 1e5 + 5;
    int n,m;
    ll a[4][N],S,ans = 0,dp[4][N],sum[4][N],mod;
    set<ll>st;
    set<ll>::iterator it;
    
    void solve1( ) {
        
        if(m == 1) ans = S % mod;
        else {
            for(int i = 1;i <= n;i ++)
              ans = max(ans,(sum[1][i] % mod + sum[2][n] - sum[2][i - 1]) % mod);
        }
    }
    
    void solve2( ) {
        
        for(int i = 1;i <= m;i ++)
          for(int j = 1;j <= n;j ++) 
            dp[i][j] = max(dp[i][j],max(dp[i][j - 1],dp[i - 1][j])) + a[i][j];
        ans = dp[m][n];
    }
    
    void solve3( ) {
        
        for(int i = 1;i <= n;i ++) {
            ll x = (sum[1][i] - sum[2][i - 1] + mod) % mod;
            st.insert(x);
            ll m = (sum[3][n] - sum[3][i - 1] + sum[2][i] + mod) % mod;
            it = st.lower_bound(mod - m);
            if(it != st.begin( )) it --;
            ans = max(ans,(m + (*it)) % mod);
            it = st.end( );
            if(it != st.begin( )) it --;
            ans = max(ans,(m + (*it)) % mod);
        }
    }
    
    ll read( ) {
        
        ll ans = 0,t = 1;
        char x; x = getchar( );
        while(x < '0' || x > '9') {
            if(x == '-') t = -1;
            x = getchar( );
        }
        while(x >= '0' && x <= '9') {
            ans = ans * 10 + x - '0';
            x = getchar( );
        }
        return ans * t;
    }
    
    int main( ) {
        
        freopen("candy.in","r",stdin);
        freopen("candy.out","w",stdout);
        scanf("%d%d%I64d",& n,& m,& mod);
        for(int i = 1;i <= m;i ++) {
            for(int j = 1;j <= n;j ++) {
                a[i][j] = read( );
                sum[i][j] = sum[i][j - 1] + a[i][j];
            }
        }
        S = 0;
        for(int i = 1;i <= m;i ++) S += sum[i][n];
        if(m <= 2) solve1( );
        else if(S < mod) solve2( );
        else solve3( );
        printf("%I64d",ans);
    }

    游戏
    【问题描述】 小明和小刚正在玩如下的游戏。首先小明画一个有N个顶点,M条边的有向图。

    然后小刚试着摧毁它。在一次操作中他可以找到图中的一个点,并且删除它所有的入边或所有的出边。

    小明给每个点定义了两个值:Wi+和Wi-。如果小刚删除了第i个点所有的入边他要给小明付Wi+元,

    如果他删除了所有的出边就需要给小明付Wi-元。 找到小刚删除图中所有边需要的最小花费。


    【输入格式】
    从文件game.in中输入数据。
    第一行有两个数N,M(1<=N<=100,1<=M<=5000)。
    第二行有N个整数,描述了N个点的Wi+,同样的第三行是这N个点的Wi-。所有的费用都是正数并且不超过10^6。接下来的M行每行有两个数,代表有向图中相应的一条边。


    【输出格式】
    输出到文件game.out中。 输出一行一个整数,即小刚的最小花费。

     

    这道题是原题了 感觉讲了好多次 

    通过题目可以发现,我们要求的就是在使用最小的点权的情况下选中所有边,

    每条边都可以被他的两个端点选中,且出入点权可能不同,于是就可以发现这是一个最小点权覆盖。 

    建边: 

    1>   先建立虚拟源S和汇T,把每个点拆成两个,ia,ib。

    2>   从S向ia连一条流量为wi-的边,从ib向T连一条流量为wi+的边。

    3>   原图中的边从ua向vb连一条流量无穷大的边。 

    4>  然后跑最大流即可。

    拆一拆点 其乐无穷 还有这道题好像必须要加当前弧优化和delta优化 不然看姜sir就活生生被卡成40分

    代码

    #include <bits/stdc++.h>
    #define oo 1e9
    using namespace std;
    
    const int N = 500;
    const int M = 1e5;
    int n,m,src,sink,w,tot = 1,ans,q[N],h[N];
    int head[N],nex[M],tov[M],f[M],dis[N];
    bool vis[N];
    
    void add(int u,int v,int w) {
        
        tot ++;
        nex[tot] = head[u];
        tov[tot] = v;
        f[tot] = w;
        head[u] = tot;
        tot ++;
        nex[tot] = head[v];
        tov[tot] = u;
        f[tot] = 0;
        head[v] = tot;
    }
    
    void add_edge( ) {
        
        src = 1,sink = 2 * n + 2;
        for(int i = n + 2;i <= 2 * n + 1;i ++) {
            scanf("%d",& w);
            add(i,sink,w);
        }
        for(int i = 2;i <= n + 1;i ++) {
            scanf("%d",& w);
            add(src,i,w);
        }
        for(int i = 1;i <= m;i ++) {
            int u,v;
            scanf("%d%d",& u,& v);
            add(1 + u,1 + n + v,oo);
        }
    }
    
    bool bfs( ) {
        
        memset(vis,0,sizeof(vis));
        memset(dis,0,sizeof(dis));
        int h = 0,t = 0;
        q[++ t] = src;
        vis[src] = true;
        while(h < t) {
            int u = q[++ h];
            for(int i = head[u];i;i = nex[i]) {
                int v = tov[i];
                if(f[i] && (! vis[v])) {
                    vis[v] = true;
                    dis[v] = dis[u] + 1;
                    q[++ t] = v;
                }
            }
        }
        return vis[sink];
    }
    
    int dfs(int u,int delta) {
        
        if(u == sink) return delta;
        int res = 0;
        for(int & i = h[u];i;i = nex[i]) {
            int v = tov[i];
            if(f[i] && delta && dis[v] == dis[u] + 1) {
                int del = dfs(v,min(delta,f[i]));
                res += del;
                delta -=del;
                f[i] -= del;
                f[i ^ 1] += del;
            }
        }
        return res;
    }
    
    int main( ) {
        
        freopen("game.in","r",stdin);
        freopen("game.out","w",stdout);
        scanf("%d%d",& n,& m);
        add_edge( );
        while(bfs( )) {
            for(int i = src;i <= sink;i ++) h[i] = head[i];
            ans += dfs(src,oo);
        }
        printf("%d",ans);
        return 0;
    }

    今天竟然是rank 2 有点小高兴..w

  • 相关阅读:
    oc基础第二天类与对象---1复习代码
    oc基础第二天类与对象---1复习
    oc基础第一天---类的方法,类与对象
    oc基础第一天---类与对象
    oc基础第一天---面向过程与面向对象
    oc基础第一天---c语言和oc语言的对比
    oc基础第一天---c语言与oc语言对比
    第一阶段c语言结晶说明
    mvc 使用json.net 替换JsonResult 默认序列化
    Mvc ModelBinder 一对多自定义数据格式 post提交
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9494474.html
Copyright © 2011-2022 走看看