• 【集合!】 20140416 && 20140417集训 总结


    mobius的奇怪演绎

         当我第一眼看见题目中出现mobius的时候,我唯一想到的就是某科学家对于n维空间的阐述与思考,同时还提出了一个mobius环。而这道题中的环就是mobius环咯。不过其实这是一道dp。。。dp的思路还是比较神。。。左括号设为+1,右括号-1.首先前面和后面有对应的规则,那么我们就做一个四维dp(dp[i][j][m][k])i表示位置,j表示正面的左括号和右括号之和,m是背面的和的最小值的abs,k是背面的和。记录m的是因为可能出现如下情况:
    __________  (mid) ________      __
        +100                       -200        +100  
    虽然l+r = 0 但是其实这是不合法的。所以dp到最后的时候就需要考虑两个条件:
    1. j >= m            2. j+k == 0  
    转移呢?分情况讨论:
    1.s[i+1] == 'S' 这种情况下肯定有dp[i+1][j+1][m][k+1] += dp[i][j][m][k];
                 而上面是j + 1,而j-1取决于j是否大于0,而且这时还需要考虑k + m == 0如果为0,那么m就要更新
                      so: if(k + m == 0) dp[i+1][j-1][m+1][k-1] += dp[i][j][m][k];
                              else dp[i+1][j-1][m][k-1] +=dp[i][j][m][k];
    2,s[i+1]=='D' 
            如果j+1,那么k--,如上考虑k与m的关系。 然后j-1只考虑j>0 方程参上或代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    int T;
    ll dp[53][53][53][121];
    char s[101]; int n = 0;
    int main()
    {
        freopen("mobius.in","r",stdin);
        freopen("mobius.out","w",stdout);
        scanf("%d",&T);
        getchar();
        while(T--)
        {
            n = 0;
            scanf("%s",s+1);
            n = strlen(s+1);
            memset(dp,0,sizeof(dp));
            dp[0][0][0][n+2] = 1;
            for(int i = 0; i < n; i++)
                for(int j = 0; j <= i; j++)
                    for(int  m = 0; m <= i; m++)
                        for(int  k = -m+n+2; k <= i+n+2; k++)
                        {
                            if(dp[i][j][m][k])
                            {
                                if(s[i+1] == 'S'){
                                    dp[i+1][j+1][m][k+1] += dp[i][j][m][k];
                                    if(j)
                                    {
                                        if(m == -(k-n-2)) dp[i+1][j-1][m+1][k-1] += dp[i][j][m][k];
                                        else dp[i+1][j-1][m][k-1] += dp[i][j][m][k];
                                    }
                                }
                                else{
                                    if(j) dp[i+1][j-1][m][k+1] += dp[i][j][m][k];
                                    if(m == -(k-n-2)) dp[i+1][j+1][m+1][k-1] += dp[i][j][m][k];
                                    else dp[i+1][j+1][m][k-1] += dp[i][j][m][k];
                                }
                            }
                        }
            ll ans = 0;
            for(int i = 0; i <= n;i++)
                for(int j = 0; j <= i;j++)
                    ans += dp[n][i][j][-i+n+2];
            printf("%lld
    ",ans);
        }
        return 0;
    }
    mobius

    某不科学的多重背包

         题目:Eden 的新背包问题

    【问题描述】

    “寄没有地址的信,这样的情绪有种距离,你放着谁的歌曲,是怎样的心情。能不能说给我听。”

    失忆的 Eden 总想努力地回忆起过去,然而总是只能清晰地记得那种思念的感觉,却不能回忆起她的音容笑貌。

    记忆中,她总是喜欢给 Eden 出谜题:在 valentines day 的夜晚,两人在闹市中闲逛时,望着礼品店里精巧玲珑的各式玩偶,她突发奇想,问了 Eden 这样的一个问题:有 n 个玩偶,每个玩偶有对应的价值、价钱,每个玩偶都可以被买有限次,在携带的价钱固定的情况下,如何选择买哪些玩偶以及每个玩偶买多少个,才能使得选择的玩偶总价钱不超过 m,且价值和最大。

    众所周知的, 这是一个很经典的多重背包问题,Eden 很快解决了,不过她似乎因为自己的问题被飞快解决感到了一丝不高兴,于是她希望把问题加难:多次询问,每次询问都将给出新的总价钱,并且会去掉某个玩偶(即这个玩偶不能被选择),再问此时的多重背包的答案(即前一段所叙述的问题)。

    这下 Eden 犯难了,不过 Eden 不希望自己被难住,你能帮帮他么?

     

    【输入格式】

    从文件 bag.in 看读入数据。

    第一行一个数 n,表示有 n 个玩偶,玩偶从 0 开始编号

    第二行开始后面的 n 行,每行三个数 ai, bi, ci,分别表示买一个第 i 个玩偶需要的价钱,获得的价值以及第 i 个玩偶的限购次数。

    接下来的一行为 q,表示询问次数。

    接下来 q 行,每行两个数 di, ei表示每个询问去掉的是哪个玩偶(注意玩偶从 0 开始编号)以及该询问对应的新的总价钱数。(去掉操作不保留,即不同询问互相独立)

     

    【输出格式】

    输出到文件 bag.out 中。

    输出 q 行,第 i 行输出对于第 i 个询问的答案。

     

    【样例输入】

    5

    2 3 4

    1 2 1

    4 1 2

    2 1 1

    3 2 3

    5

    1 10

    2 7

    3 4

    4 8

    0 5

    【样例输出】

    13

    11

    6

    12

    4

    【样例说明】

    一共五种玩偶, 分别的价钱价值和限购次数为(2,3,4) (1,2,1) (4,1,2)(2,1,1)(3,2,3)

    五个询问,以第一个询问为例。第一个询问表示的是去掉编号为 1 的玩偶,且拥有的钱数为 10 时可以获得的最大价值,则此时剩余玩偶为(2,3,4)(4,1,2)(2,1,1)(3,2,3),若把编号为 0 的玩偶买 4 个(即全买了) ,然后编号为 3 的玩偶买一个, 则刚好把 10元全部花完, 且总价值为 13 可以证明没有更优的方案了。

    注意买某种玩偶不一定要买光。

     

    【数据规模与约定】

    10%数据满足 1  n  10

     20%数据满足 1  n  100, ci = 1, 1  q  100

     20%数据满足 1  n  100, 1  q  100

     30%数据满足 c= 1

    100%数据满足 1  n  1000, 1  q  3*105,1  aibici  100, 0  di < n,  0  ei  1000
            

        为什么一开始要贴题目呢?因为这道题原来bzoj上面有,现在被他们封权限了,要交钱才能看。so,以后看方便(bzoj丧心病狂,原来的良心呢?)
        贴这道题主要是因为几点启示:
        1.一定要注意空间的问题,并且c++ 如果开小了有可能不会re。。坑!
        2.看到如此的询问,直接考虑预处理吧。这道题利用只有一个物品会被ban掉,所以就预处理出1-i,容量为j的最大价值和i-n,容量为j的最大价值。注意这里是可以递推的。f[i][j] = f[i-1][j] 然后在在现在的i物品上dp,减少计算量。不减少——手测比暴力还低。。。
        3.注意编号问题!

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 using namespace std;
     6 
     7 int n,q;
     8 int num[1010],w[1010],v[1010];
     9 int f[1020][1020];
    10 int g[1020][1020];
    11 
    12 int main()
    13 {
    14     freopen("bag.in","r",stdin);
    15     freopen("bag.out","w",stdout);
    16     scanf("%d",&n);
    17     memset(f,0,sizeof(f));
    18     memset(g,0,sizeof(g));
    19     memset(num,0,sizeof(num));
    20     memset(w,0,sizeof(w));
    21     memset(v,0,sizeof(v));
    22     for(int i = 1; i <= n; i++)
    23         scanf("%d%d%d",&w[i],&v[i],&num[i]);
    24     for(int i = 1; i <= n; i++)
    25     {
    26         for(int j = 0; j <= 1001; j++)
    27             f[i][j] = f[i-1][j];
    28         for(int k = 1;k <= num[i];k++)
    29             for(int t = 1001;t >= 0; t--)
    30                 if(t >= w[i]) f[i][t] = max(f[i][t],f[i][t-w[i]]+v[i]);
    31     }
    32     for(int i = n;i >0;i--)
    33     {
    34         for(int j = 0; j <= 1001; j++)
    35             g[i][j] = g[i+1][j];
    36         for(int k = 1; k <= num[i];k++)
    37             for(int t = 1001; t >= 0; t--)
    38                 if(t >= w[i]) g[i][t] = max(g[i][t],g[i][t-w[i]]+v[i]);
    39     }
    40     scanf("%d",&q);
    41     while(q--)
    42     {
    43         int t,mark;
    44         scanf("%d%d",&mark,&t);
    45         mark ++;
    46         if(mark == 1) printf("%d
    ",g[2][t]);
    47         else if(mark == n) printf("%d
    ",f[n-1][t]);
    48         else{
    49             int ans = 0;
    50             for(int j = 0; j <= t;j++)
    51                 ans = max(ans,f[mark-1][j]+g[mark+1][t-j]);
    52             printf("%d
    ",ans);
    53         }
    54     }
    55     return 0;
    56 }
    bag

    bzoj 刷题路

        首先跪拜hja。
        跪毕,起身说正事。今天我竟然调了一个早上的1001,然后又调了一个晚上的1002,我是不是没救了。。
        第一道题,就是某周大神在2007还是08年的的某ppt中的最大最小定理解析,其中提到了s-t平面图用对偶图的方法来做,不过原理我不怎么太懂,也就是不会推导,所以只能是比较弱的记录下来。根据Symon Yang的说法,这种题的图都相当的规整,所以对于对偶面的确定一般比较简单。不过既然在标号上降低难度,那么点基本都是10^6级的了,so,想到用对偶图的边来表示割,然后跑一遍spfa或dijkstra+heap就可以了。不过由于对自己的dijkstra毫无信心,所以我还是spfa算了。那么有什么注意的呢?那就是慢慢推导编号,不要捉急,慢慢来。还有如果是spfa要开一个循环队列,只需要在下标那里mod一个点数就好。(为什么是点数呢?因为如果开小了那么又可能前面的某些没有出列的元素被覆盖掉了,导致算法出错(我会告诉你我调了一个小时吗?)其余倒没什么了。

      1 #include <iostream> 
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <cstring>
      5 using namespace std;
      6 int n,m;
      7 int heng[1001][1001],shu[1010][1010],xie[1010][1010];
      8 struct edge{
      9     int t,d;
     10     edge* next;
     11 }e[8000010],*head[2000010];
     12 int ne = 0;
     13 void addedge(int f,int t,int d)
     14 {
     15     e[ne].t = t,e[ne].d = d;
     16     e[ne].next = head[f];
     17     head[f] = e + ne++;
     18     e[ne].t = f,e[ne].d = d;
     19     e[ne].next = head[t];
     20     head[t] = e + ne++;
     21 }
     22 int s,t;
     23 int dis[3000001];
     24 bool in[3000001];
     25 int q[1000001];
     26 int l,r;
     27 int spfa(int s,int t)
     28 {
     29     int ql=1000000;
     30     memset(dis,0x3f3f3f3f,sizeof(dis));
     31     memset(in,false,sizeof(in));
     32     memset(q,0,sizeof(q));
     33     in[s] = true;
     34     l = 0, r = 0;
     35     q[r++ % ql] = s; 
     36     dis[s] = 0;
     37     while(l < r)
     38     {
     39         int now = q[l++ % ql];
     40         in[now] = false;
     41         for(edge* p = head[now];p;p = p->next)
     42             if(dis[p->t] > dis[now] + p->d){
     43                 dis[p->t] = dis[now] + p->d;
     44                 if(in[p->t] == false) {
     45                     q[r++ % ql] = p->t,in[p->t] = true;
     46                 }
     47             }
     48     }
     49     return dis[t];
     50 }
     51 int main()
     52 {
     53     freopen("cs.in","r",stdin);
     54     memset(heng,0,sizeof(heng));
     55     memset(shu,0,sizeof(shu));
     56     memset(head,NULL,sizeof(head));
     57     scanf("%d%d",&n,&m);
     58     if( n == 1 || m == 1)
     59     {
     60         int k  = max(n,m);
     61         int ans = 0x3f3f3f3f;
     62         for(int i = 1; i < k; i++)
     63         {
     64             int x;
     65             scanf("%d",&x);
     66             ans = min(ans,x);
     67         }
     68         printf("%d",ans);
     69         return 0;
     70     }
     71     for(int i = 1;i <= n; i++)
     72         for(int j = 1; j < m; j++)
     73             scanf("%d",&heng[i][j]);
     74     for(int i = 1; i <= n-1;i++)
     75         for(int j = 1; j <= m; j++)
     76             scanf("%d",&shu[i][j]);
     77     for(int i = 1; i <= n-1;i++)
     78         for(int j = 1; j <= m-1;j++)
     79             scanf("%d",&xie[i][j]);
     80     s = 0;
     81     t = n*(m-1) + m*(n-1) + (m-1)*(n-1) - n * m + 2;
     82     for(int  i = 1; i <= n; i++)
     83         for(int j = 1;j < m; j++)
     84         {
     85             if(i == 1){addedge(t,(i-1)*(m-1)*2+j*2,heng[i][j]);}
     86             else if( i == n) {addedge((i-2)*(m-1)*2+j*2-1,s,heng[i][j]);}
     87             else addedge((i-1)*(m-1)*2+j*2,(i-2)*(m-1)*2+j*2-1,heng[i][j]);
     88         }
     89     for(int i = 1; i < n; i++)
     90         for(int j = 1; j <= m; j++)
     91         {
     92             if(j == 1){addedge(s,(i-1)*(m-1)*2+(j-1)*2+1,shu[i][j]);}
     93             else if( j == m){addedge(t,(i-1)*(m-1)*2+(j-1)*2,shu[i][j]);} 
     94             else addedge((i-1)*(m-1)*2+(j-1)*2,(i-1)*(m-1)*2+(j-1)*2+1,shu[i][j]);
     95         }
     96     for(int i = 1; i < n; i++)
     97         for(int j = 1; j < m;j++)
     98             addedge((i-1)*(m-1)*2+(j-1)*2+1,(i-1)*(m-1)*2+j*2,xie[i][j]);
     99     printf("%d
    ",spfa(s,t));
    100     return 0;    
    101 }
    View Code

    注意数组一定不要开小了,我re了7次还是8次。。。

    还有就是1002这道神题。这道题第一要知道递推式,然后还要写高精。像这种找规律我一般都跪了。。不过这个题找递推式的正确方法是基尔霍夫矩阵来求,有时间再探讨好了,我还是不要作死了,no zuo no die。。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 int n;
     7 int a[1001];
     8 int b[1001];
     9 int len1, len2;
    10 void cal()
    11 {
    12     int temp[1001];
    13     memset(temp,0,sizeof(temp));
    14     int len = 0;
    15     for(int i = 0; i < len1;i++)
    16     {
    17         temp[i] += a[i]*3;
    18         temp[i+1] += temp[i]/10;
    19         temp[i] = temp[i]%10;
    20     }
    21     if(temp[len1] != 0) len = len1 + 1;
    22     else len = len1;
    23     for(int i = 0; i < min(len,len2);i++)
    24     {
    25         if(temp[i] < b[i]) temp[i+1]--,temp[i]+= 10;
    26         temp[i] = temp[i] - b[i];
    27     }
    28     if(temp[len-1] == 0) len--; 
    29     temp[0] += 2;
    30     int now = 0;
    31     while(temp[now] >= 10){temp[now+1] += 1, now++;temp[now-1] %= 10;}
    32     if(now == len) len++;
    33     int t[1000];
    34     for(int i = 0; i < len1;i++)
    35         t[i] = a[i];
    36     for(int i = 0; i < len;i++)
    37         a[i] = temp[i];
    38     for(int i = 0; i < len1;i++)
    39         b[i] = t[i]; 
    40     len2 = len1;
    41     len1 = len;
    42 }
    43 int main()
    44 {
    45     scanf("%d",&n);
    46     a[0] = 1;
    47     b[0] = 0;
    48     len1 = 1;
    49     len2 = 0;
    50     for(int i = 2; i <= n;i++)
    51         cal();
    52     for(int i = len1 - 1; i >= 0; i--)
    53         printf("%d",a[i]);
    54 }
    View Code

    高精真是写死人。。要不是省选只能用c,c++,pascal果断python,java(其实主要我不会java和python = =b。。。)
    不过张老师给我说了一个dp:
        对于第i个点,然后进行分割,相当于这一状态的某种情况是由某两种已知的情况拼出来的。。。。只能说。。我明天再去问问。。
    再跪hja! 

  • 相关阅读:
    黄聪:C#中CefSharp的简单使用
    ArcGIS Pro关闭窗口和退出
    AddOverlay
    ArcGIS Pro固定纸张限定比例尺自动调整纵横打印
    ArcGIS pro增加一个独立表到地图
    ArcGIS Pro How to remove standalone table from contents
    ArcGIS Pro的进度条
    CreatePolygonGraphicElement
    Creating a Group with a List of Elements
    ArcGISPro理解多线程
  • 原文地址:https://www.cnblogs.com/ianaesthetic/p/3672890.html
Copyright © 2020-2023  润新知