• 2019 CCPC-Wannafly Winter Camp Day1 (Div2, onsite)


    solve:4/11

    补题:6/11

    A 机器人 

    补题:zz

    这是一道分类讨论的题目,有一个规律就是如果必须要从第一个区到第二个区,那么最多转区两次(1到2一次,2到1一次),然后分类讨论即可,只要细心一定能做出来。

    //#pragma comment(linker, "/STACK:102400000,102400000")
    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<string>
    #include<math.h>
    #include<cmath>
    #include<time.h>
    #include<map>
    #include<set>
    #include<vector>
    #include<queue>
    #include<algorithm>
    #include<numeric>
    #include<stack>
    #include<bitset>
    #include<unordered_map>
    const int maxn = 0x3f3f3f3f;
    const double EI = 2.71828182845904523536028747135266249775724709369995957496696762772407663035354594571382178525166427;
    const double PI = 3.141592653589793238462643383279;
    //#ifdef TRUETRUE
    //#define gets gets_s
    //#endif
    using namespace std;
    int c[2][1000010];
    int z[2][100010], cnt[5];
    int d[111];
    int main(void)
    {
        //ios::sync_with_stdio(false);
        int n, rr, k, m, s, i, x, y, l1, l2, r1, r2, ans, l, r, j;
        while (~scanf("%d %d %d %d %d", &n, &rr, &m, &k, &s))
        {
            memset(c, 0, sizeof(c));
            cnt[0] = 0;
            cnt[1] = 0;
            for (i = 0; i < rr; i++)
            {
                scanf("%d %d", &x, &y);
                if (x == s && y == 0)
                {
                    continue;
                }
                c[y][x] = 1;
                z[y][cnt[y]++] = x;
            }
            for (i = 0; i < m; i++)
            {
                scanf("%d", d + i);
            }
            sort(z[0], z[0] + cnt[0]);
            sort(z[1], z[1] + cnt[1]);
            l1 = -1;
            l2 = -1;
            r1 = -1;
            r2 = -1;
            if (cnt[0])
            {
                l1 = z[0][0];
                r1 = z[0][cnt[0] - 1];
            }
            if (cnt[1])
            {
                l2 = z[1][0];
                r2 = z[1][cnt[1] - 1];
            }
            ans = 0;
            if (l2 != -1)
            {
                ans += k * 2;
            }
            l = min(l1, l2);
            if (l1 == -1)
            {
                l = l2;
            }
            else if (l2 == -1)
            {
                l = l1;
            }
            r = max(r1, r2);
            d[m++] = 1;
            d[m++] = n;
            d[m++] = n + 1;
            sort(d, d + m);
            /*for (i = 0;i < m;i++)
            {
            printf("%d ", d[i]);
            }
            printf("
    ");*/
            //printf("l = %d  r = %d
    ", l, r);
            if (r <= s && r != -1 && l != -1)
            {
                //printf("l = %d  r = %d
    ",l,r);
                for (i = 0; i < m; i++)
                {
                    if (d[i] <= l && d[i + 1] > l)
                    {
                        break;
                    }
                }
                ans += s - d[i];
                //printf("ans = %d
    ",ans);
                if (l2 != -1)
                {
                    for (j = 0; j < m; j++)
                    {
                        if (d[j] >= r2)
                        {
                            break;
                        }
                    }
                    ans += d[j] - d[i];
                    ans += abs(s - d[j]);
                }
                else
                {
                    ans += s - d[i];
                }
            }
            else if (l >= s && r != -1 && l != -1)
            {
                for (i = 0; i < m; i++)
                {
                    if (d[i] >= r)
                    {
                        break;
                    }
                }
                ans += d[i] - s;
                if (l2 != -1)
                {
                    for (j = m - 1; j >= 0; j--)
                    {
                        if (d[j] <= l2)
                        {
                            break;
                        }
                    }
                    ans += d[i] - d[j];
                    ans += abs(s - d[j]);
                }
                else
                {
                    ans += d[i] - s;
                }
            }
            else if (l <= s && r >= s && r != -1 && l != -1)
            {
                for (i = 0; i < m; i++)
                {
                    if (d[i] <= l && d[i + 1] > l)
                    {
                        break;
                    }
                }
                //printf("   %d
    ",ans);
                ans += 2 * (s - d[i]);
                //printf("   %d %d %d %d %d
    ", ans,d[i],i,l,r);
                for (i = 0; i < m; i++)
                {
                    if (d[i] <= r && d[i + 1] >= r)
                    {
                        break;
                    }
                }
                ans += 2 * (d[i + 1] - s);
                //printf("   %d %d
    ", ans,d[i + 1]);
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    View Code

    B 吃豆豆

    Code:pai爷

    Thinking: pai爷  KK

          dp[ i ][ j ][ k ]表示 i 行 j 列 在第 k 秒的时候吃到的最多的豆豆数量,从五个方向转移(上下左右加自己)。k的范围最大只有1018*10,然后用滚动数组滚动掉,就可以AC了。

    补充:div1 1018变成了10^18,会有周期,尚未证明,k,k+t,k+2t。

    #include<stdio.h>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int ans=0,n,m,c,now=0,X1,X2,Y1,Y2,f[3][20][20],t[20][20];
    void solve(int a,int b,int c,int d,int k) {
        if(t[a][b]!=0 && (k%t[a][b]==0)) f[!now][a][b]=max(f[now][c][d]+1,f[!now][a][b]);
        else f[!now][a][b]=max(f[now][c][d],f[!now][a][b]);
    }
    int main() {
        scanf("%d%d%d",&n,&m,&c);
        for(int i=1; i<=n; i++)
            for(int j=1; j<=m; j++) scanf("%d",&t[i][j]);
        scanf("%d%d%d%d",&X1,&Y1,&X2,&Y2);
        for(int k=0; k<=1; k++)
            for(int i=1; i<=n; i++)
                for(int j=1; j<=m; j++) f[k][i][j]=-1;
        f[now][X1][Y1]=0;
        for(int k=1; k<=11000; k++) {
            for(int i=1; i<=n; i++)
                for(int j=1; j<=m; j++)
                    if(f[now][i][j]!=-1) {
                        solve(i+1,j,i,j,k);
                        solve(i-1,j,i,j,k);
                        solve(i,j+1,i,j,k);
                        solve(i,j-1,i,j,k);
                        solve(i,j,i,j,k);
                        if(f[!now][X2][Y2]>=c) ans=k;
                    }
            if(ans) break;
            now=!now;
        }
        printf("%d
    ",ans);
    }
    View Code

    C  拆拆拆数

    unsolved

    D 超难的数学题

    unsolved

    E 流流流动

    补题:kk

    树形dp,比赛没人做,以为是难题。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #define CLR(a,b) memset(a,b,sizeof(a));
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int maxn=10010;
    int head[maxn],tot,n;
    bool vis[maxn];
    int f[maxn],d[maxn];
    int dp[2][maxn];
    struct edge{
        int v,Next;
    }a[maxn<<2];
    void init(){
        tot=0,CLR(head,-1);
        CLR(vis,false);
        CLR(dp,0);
    }
    void addv(int u,int v)
    {
        a[++tot].v=v;
        a[tot].Next=head[u];
        head[u]=tot;
    }
    void tdfs(int u,int fa){
        int flag=0;
        vis[u]=1;
        dp[0][u]=0;
        dp[1][u]=f[u];
        for(int i=head[u];i!=-1;i=a[i].Next)
        {
            int v=a[i].v;
            if(v==fa)continue;
            tdfs(v,u);
            flag=1;
            dp[0][u]+=max(dp[0][v],dp[1][v]);
            dp[1][u]+=max(dp[0][v],dp[1][v]-d[min(u,v)]);
        }
    }
    int main(){
        cin>>n;
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&f[i]);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&d[i]);
        }    
        for(int i=2;i<=n;i++)
        {
            
            if(i%2==1)
            {
                addv(i,3*i+1);
                addv(3*i+1,i);
            }
            if(i%2==0){
                addv(i,i/2);
                addv(i/2,i);
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==0){
                tdfs(i,0);
                ans+=max(dp[0][i],dp[1][i]);
            }
        }
        printf("%d
    ",ans);
    }
    View Code

    F 爬山

    Code:KK

    Thinking:KK

          对于一座山,如果要砍,就肯定要砍到(K+第一座山的高度),将这部分额外的花费加到边的权值上就好了,双向边要分开建,权值不一定一样,然后dijkstra跑一跑,水题。

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<stdlib.h>
     4 #include<string.h>
     5 #include<string>
     6 #include<math.h>
     7 #include<cmath>
     8 #include<time.h>
     9 #include<map>
    10 #include<set>
    11 #include<vector>
    12 #include<queue>
    13 #include<algorithm>
    14 #include<numeric>
    15 #include<stack>
    16 #include<bitset>
    17 //#include<unordered_map>
    18 const int inf = 0x3f3f3f3f;
    19 const double EI = 2.71828182845904523536028747135266249775724709369995957496696762772407663035354594571382178525166427;
    20 const double PI = 3.141592653589793238462643383279;
    21 const int maxn=100010;
    22 using namespace std;
    23 typedef long long ll;
    24 int n,m;
    25 ll k;
    26 int head[maxn],tot;
    27 ll dis[maxn];
    28 
    29 struct edge{
    30     int v;
    31     ll w;
    32     int Next;
    33 }a[maxn<<2];
    34 bool vis[maxn];
    35 ll h[maxn];
    36 void init(){
    37     tot=0,memset(head,-1,sizeof(head));
    38 }
    39 void addv(int u,int v,ll w)
    40 {
    41     a[++tot].v=v;
    42     a[tot].w=w;
    43     a[tot].Next=head[u];
    44     head[u]=tot;
    45 }
    46 priority_queue< pair<ll,int>>q;
    47 void dijkstra(){
    48     memset(vis,false,sizeof(vis));
    49     memset(dis,0x3f,sizeof(dis));
    50     dis[1]=0;
    51     q.push(make_pair(0,1));
    52     while(!q.empty()){
    53         int x=q.top().second;
    54         q.pop();
    55         if(vis[x])continue;
    56         vis[x]=1;
    57         for(int i=head[x];i!=-1;i=a[i].Next)
    58         {
    59             int y=a[i].v;
    60             ll w=a[i].w;
    61             if(dis[y]>dis[x]+w){
    62                 dis[y]=dis[x]+w;
    63                 q.push(make_pair(-dis[y],y));
    64             }
    65         }
    66     }
    67 }
    68 int main(void)
    69 {
    70     //ios::sync_with_stdio(false);
    71     cin>>n>>m>>k;
    72     init();
    73     scanf("%lld",&h[1]);
    74     k+=h[1];
    75     for(int i=2;i<=n;i++)
    76     {
    77         scanf("%lld",&h[i]);
    78     }
    79     int u,v;
    80     ll w;
    81     while(m--)
    82     {
    83         scanf("%d%d%lld",&u,&v,&w);
    84         if(h[v]>=k)
    85         addv(u,v,w+(h[v]-k)*(h[v]-k));
    86         else addv(u,v,w);
    87         if(h[u]>=k)
    88         addv(v,u,w+(h[u]-k)*(h[u]-k));
    89         else addv(v,u,w);
    90     }
    91     dijkstra();
    92     printf("%lld
    ",dis[n]);
    93     return 0;
    94 }
    View Code

    G  双重矩阵

    unsolved

    H 我爱割葱

    unsolved

    I 起起落落

    Code:pai爷

    Thinking:pai爷

    div 2 树状数组+dp思想 O(n*n*log(n))

     1 #include<stdio.h>
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<cmath>
     7 using namespace std;
     8 const int P=1e9+7;
     9 int n,p[2010],w[2010],c[10100],q[2010][2010];
    10 int ans=0;
    11 inline int lowbit(int x){return x&-x;} 
    12 void add(int x,int y)
    13 {
    14     for(;x<=n;x+=lowbit(x)) c[x]=(c[x]+y)%P;
    15 }
    16 int sum(int x)
    17 {
    18     int tmp=0;
    19     for(;x;x-=lowbit(x)) tmp=(tmp+c[x])%P;
    20     return tmp;
    21 }
    22 int main()
    23 {
    24     scanf("%d",&n);
    25     for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    26     for(int i=1;i<=n;i++)
    27        for(int j=i+1;j<=n;j++)
    28        {
    29             if(p[i]<p[j])
    30             {
    31                q[i][0]++;
    32             q[i][q[i][0]]=j;    
    33             //printf("%d %d
    ",i,j);
    34          }
    35        }
    36     for(int i=n;i>=1;i--)
    37     {
    38         w[i]=sum(p[i]-1);
    39         ans=(ans+w[i])%P;
    40         //printf("%d
    ",ans);
    41         w[i]++;
    42         for(int j=1;j<=q[i][0];j++) add(p[q[i][j]],w[q[i][j]]);
    43     }
    44     printf("%d
    ",ans);
    45 }
    View Code

    J 夺宝奇兵

    Code:zz

    Thinking:KK zz

    div2:由于m最大只有一千,所以从(m+1)/2到1枚举最后我需要买的物品,每次和当前答案更新。如一个人的物品比自己需要买的多或一样多,那肯定先把多余这部分的全部买走,如果发现不够,那么就在剩下的所有里面挑最便宜的;如果发现买完那些比自己大的,就已经超出当前的值了,说明不合法,就不更新答案。用multiset完成以上操作。

    div1:m变成一万,不能枚举,想到二分,发现中间有一段区间虽然都是合法的,但是并不是买的物品越少钱越少(买的物品多了,强制买的物品就少,然后不足的就可以从其他物品里挑最便宜的),所以不满足二分的性质,三分好像可以做(wls吐槽好像二字),标算是线段树?还不会。

     1 //#pragma comment(linker, "/STACK:102400000,102400000")
     2 #include<iostream>
     3 #include<stdio.h>
     4 #include<stdlib.h>
     5 #include<string.h>
     6 #include<string>
     7 #include<math.h>
     8 #include<cmath>
     9 #include<time.h>
    10 #include<map>
    11 #include<set>
    12 #include<vector>
    13 #include<queue>
    14 #include<algorithm>
    15 #include<numeric>
    16 #include<stack>
    17 #include<bitset>
    18 //#include<unordered_map>
    19 const int inf = 0x3f3f3f3f;
    20 const int maxn=100010;
    21 using namespace std;
    22 typedef long long ll;
    23 struct s
    24 {
    25     long long c[1010];
    26     int cnt;
    27 }z[1010];
    28 multiset<long long>st;
    29 multiset<long long>::iterator it;
    30 inline bool comp(ll a,ll b)
    31 {
    32     return a > b;
    33 }
    34 int main(void)
    35 {
    36     //ios::sync_with_stdio(false);
    37     int n,m,i,z2,j,num,x,k;
    38     long long z1,sum,ans,ss;
    39     while(~scanf("%d %d",&n,&m))
    40     {
    41         st.clear();
    42         for(i = 1;i <= n;i++)
    43         {
    44             z[i].cnt = 0;
    45         }
    46         for(i = 0;i < m;i++)
    47         {
    48             scanf("%lld %d",&z1,&z2);
    49             z[z2].c[z[z2].cnt++] = z1;
    50             st.insert(z1);
    51         }
    52         for(i = 1;i <= n;i++)
    53         {
    54             sort(z[i].c,z[i].c + z[i].cnt,comp);
    55         }
    56         sum = 0;
    57         num = 0;
    58         ans = 10000000000000;
    59         for(i = m / 2 + 1;i >= 1;i--)
    60         {
    61             for(j = 1;j <= n;j++)
    62             {
    63                 if(z[j].cnt >= i)
    64                 {
    65                     while(z[j].cnt >= i)
    66                     {
    67                         num++;
    68                         sum += z[j].c[z[j].cnt - 1];
    69                         st.erase(st.find(z[j].c[z[j].cnt - 1]));
    70                         z[j].cnt--;
    71                     }
    72                 }
    73             }
    74             if(num == i)
    75             {
    76                 ans = min(sum,ans);
    77             }
    78             else if(num < i)
    79             {
    80                 ss = sum;
    81                 x = i - num;
    82                 for(it = st.begin();it != st.end();it++)
    83                 {
    84                     sum += *it;
    85                     x--;
    86                     if(x == 0)
    87                     {
    88                         break;
    89                     }
    90                 }
    91                 ans = min(sum,ans);
    92                 sum = ss;
    93             }
    94         }
    95         printf("%lld
    ",ans);
    96     }
    97     return 0;
    98 }
    View Code

    K 星球大战

    unsolved

    建bfs树

    训练总结:

    KK: 简单dp听了pai爷的一些思路马上意会到正解。最短路看错样例,看清后秒解,然后oj的排名炸了,以为今天只能做两题,所以在梦游想题,后来发现J题数据量小,想了一下想到div2的正解,被zz优化了一下,刚好过了,自己写可能会wa一发(因为没有二分的性质,但是自己写可能会找到一个答案就直接break),以后训练要认真,很多题都是可以思考的,不到最后不要放弃。

    pai爷:做题的时候缺少验证吧,不够认真对待题目,思路要清晰,想法很多,错误想法也很多。之后要大胆猜测以及大胆验证。

    zz:一开局看到了B,感觉和以前做的一道题很像,想到可能是一个三重循环的dp,但是时间那一维和状态转移方程没想好,就没说,看其他题去了;后来oj出了问题,基本上没更新,题目基本上没什么思路,过了很久以后,kk跟我说了J题的暴力做法,我看了看n和m才一千,感觉行,后来在写的时候发现太暴力是要n^3的,就用multiset降到了n*n*log(n),刚好过(因为comp函数写错了wa了,哭了)。

  • 相关阅读:
    P2168 [NOI2015]荷马史诗
    P3195 [HNOI2008]玩具装箱TOY
    P1972 [SDOI2009]HH的项链
    P2339 提交作业usaco
    P3974 [TJOI2015]组合数学
    P2831 愤怒的小鸟
    [校内模拟题4]
    P3952 时间复杂度
    P3531 [POI2012]LIT-Letters
    2019.10.1 qbxt模拟题
  • 原文地址:https://www.cnblogs.com/mountaink/p/10296396.html
Copyright © 2020-2023  润新知