【62测试】【状压dp】【dfs序】【线段树】

第一题:

  给出一个长度不超过100只包含'B'和'R'的字符串,将其无限重复下去。
  比如,BBRB则会形成
  BBRBBBRBBBRB
  现在给出一个区间[l,r]询问该区间内有多少个字符'B'(区间下标从1开始)   [1<=l,r<=1e18]
解:  没想到第一题这么水。直接前缀和+mod就可以了,再判一下边界。注意1e18不需要高精度。long long 有9*10^18.

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 105
 6 #define ll long long
 7 using namespace std;
 8 char c[maxn];
 9 ll len,ans,l,r,sum[maxn];
10 int main()
11 {
12     freopen("a.in","r",stdin);
13     freopen("a.out","w",stdout);
14     scanf("%s",c+1);
15     cin>>l>>r;
16     len=strlen(c+1);
17     for (int i=1;i<=len;i++)
18      {
19          sum[i]=sum[i-1];
20          if (c[i]=='B') sum[i]++;
21      } 
22     ans=(r/len)*sum[len]+sum[r%len]-(l/len)*sum[len]-sum[l%len];
23     if ((l%len==0&&c[len]=='B')||c[l%len]=='B') ans++;
24     printf("%I64d",ans);
25     return 0;
26 }

第二题:(codeforces 580D:Kefa and Dishes)

  我们要从n种食物选m个出来,安排一个顺序吃掉它(们),每种食物有个美味值ai,然后我们有k个规则,每个规则有 xi, yi 和 ci三个数,如果吃完第xi种食物接下来马上吃第yi种食物,第j种食物的美味值会增加ci。每种食物至多吃一个,求美味值最大的和是多少?

  n,m<=18,ai,ci<=10^9

解:

   看到这么小的数据范围就是状压dp了。想到是第一次自己写,还是很欣慰的得了50%。我的方法是f[i][j]表示选了 i 个的状态 j 。写转移方程的时候遇到了问题,不能表示上一个选的是什么(而从这一点出发可以想到换第一维的表示,可以换为last取的食物,于是我与标答失之交臂)所以把 f 写了一个结构体,存下美味值和上一次选的食物。然后就是转移方程,我先循环m,然后枚举所有状态,判断该状态是否符合只取了当前个食物,然后枚举n,加入下一个状态。

  还是不知道为什么WA了5个点,等写完博客来看看。

  50分代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define M 300000
 6 #define maxn 20
 7 #define ll long long
 8 using namespace std;
 9 int n,m,k,ma;
10 ll v[maxn];
11 struct pp{
12     ll tastyy;
13     int chos;    
14 };
15 pp f[maxn][M];
16 ll ad[maxn][maxn];
17 bool pd(int x,int y)
18 {
19     int sum=0;
20     for (int i=0;i<n;i++)
21      {
22          if ((1<<i)&x) sum++; 
23          if (sum>y-1) return false; 
24      } 
25     if (sum==y-1) return true;
26     else return false;
27 }
28 int main()
29 {
30     freopen("b.in","r",stdin);
31     freopen("b.out","w",stdout);
32     scanf("%d%d%d",&n,&m,&k);
33     for (int i=1;i<=n;i++)
34       scanf("%I64d",&v[i]);
35     for (int i=1;i<=k;i++)
36     {
37         int x,y;
38         ll z;
39         scanf("%d%d%I64d",&x,&y,&z);
40         ad[x][y]=z;
41     }
42     for (int i=1;i<=m;i++)
43      {
44          f[i][0].tastyy=-1;
45          ma=(ma|(1<<(n-i)));//n-i
46      } 
47     for (int i=1;i<=n;i++)
48       {
49           int x=(1<<(i-1));// not f[1][i]
50           f[1][x].tastyy=v[i];
51           f[1][x].chos=i;
52       }
53     for (int i=2;i<=m;i++)
54     {
55         for (int j=1;j<=ma;j++)
56         if (pd(j,i)&&f[i-1][j].tastyy){
57             for (int k=1;k<=n;k++)
58             if (f[i][(j&(1<<(k-1)))].tastyy==-1){
59                 int cur=(j|(1<<(k-1)));//k-1
60                 ll add=0; 
61                 if (ad[f[i-1][j].chos][k]) add=ad[f[i-1][j].chos][k];
62                 if (f[i-1][j].tastyy+v[k]+add>=f[i][cur].tastyy){//放在括号内 
63                     f[i][cur].tastyy=f[i-1][j].tastyy+v[k]+add;
64                     f[i][cur].chos=k;
65                 }
66             }
67         }
68     }
69     ll ans=0;
70     for (int i=1;i<=ma;i++)
71     if (f[m][i].tastyy>=0){
72         if (f[m][i].tastyy>=ans) ans=f[m][i].tastyy;
73     }
74     printf("%I64d",ans);
75     return 0;
76 }
View Code

  说说正解。这道题当初电子科大那位讲过,我说怎么这么眼熟。用f[i][j]表示最后一个选 j 的状态 i 。第一层枚举所有状态,进入后判断是否选了m个更新答案,否则,第二层循环当前要选的点,如果当前状态没有选过,那么进入第三层,循环上一次能选的点,更新状态:f[(i|(1<<(j-1)))][j]=max(f[(i|(1<<(j-1)))][j],f[i][k]+ad[k][j]+v[j]) 。

  AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define M 300000
 6 #define maxn 20
 7 #define ll long long
 8 using namespace std;
 9 int n,m,k;
10 ll v[maxn],f[M][maxn],ad[maxn][maxn],ans;
11 bool pd(int x)
12 {
13     int sum=0;//sum=0
14     for (int i=1;i<=n;i++)
15      if ((1<<(i-1))&x) sum++;//&x
16     if (sum==m) return true;
17     else return false; 
18 }
19 int main()
20 {
21     freopen("b.in","r",stdin);
22     freopen("b.out","w",stdout);
23     cin>>n>>m>>k;
24     for (int i=1;i<=n;i++)
25       scanf("%I64d",&v[i]);
26     for (int i=1;i<=k;i++)
27     {
28         int x,y;
29         ll z;
30         scanf("%d%d%I64d",&x,&y,&z);
31         ad[x][y]=z;
32     }
33     for (int i=0;i<n;i++)
34       f[(1<<i)][i+1]=v[i+1];
35     int idx=1;
36     for (int i=1;i<=(1<<n);i++)
37     {
38         if (pd(i)){
39             for (int j=1;j<=n;j++)
40               if (f[i][j]>ans) ans=f[i][j];
41         }
42         else{
43             for (int j=1;j<=n;j++)
44             {
45                 if (((i>>(j-1))&1)==0)
46                 {//没有吃 
47                     for (int k=1;k<=n;k++)
48                       if ((i>>(k-1))&1)//枚举吃过的最后一个 
49                       {
50                           if (f[i][k]+ad[k][j]+v[j]>f[(i|(1<<(j-1)))][j])
51                           f[(i|(1<<(j-1)))][j]=f[i][k]+ad[k][j]+v[j];
52                       }        
53                 }
54             }
55         }
56     }
57     printf("%I64d",ans);
58     return 0;
59 }

第三题:

  因为外来的入侵,国王决定在某些城市加派士兵。所有城市初始士兵数量为0。当城市i被加派了k名士兵时。城市?的所有子城市需要被加派k + 1名士兵。这些子城市的所有子城市需要被加派k +2名士兵。以此类推。当然,加派士兵的同时,国王也需要不断了解当前的情况。于是他随时可能询问以城市 i 为根的子树中的所有城市共被加派了多少士兵。你现在是国王的军事大臣,你能回答出国王的每个询问么?

  输入格式
第一行,包含两个整数N,P代表城市数量以及国王的命令的数量。
第二行N −1个整数,表示2− N号每个节点的父亲节点。
接下来的P行,每行代表国王的一个命令,命令分两种:
A X K在城市X加入K个士兵
Q X 询问以城市X为根的子树中所有士兵数量的和。

  n<=50000,p<=100000

解:  考试时用20多分钟打的暴力,过了50%。然后这套题就考了200。这是集训以来考的最好的一次,第4吧。

  说正事。这道题的正解:dfs序+线段树。

  dfs序:按照dfs的搜索顺序,一个节点的所有子树都是连续的标号,所以对于这个节点有一个最大区间,可以用线段树进行维护。(QAQ树套树-_-)

  最终还是逃不过线段树。每一次操作u节点对于u的某一子树上的节点v而言,需要加上的值为k+dep[v]-dp[u]. dep[v]为节点本身的性质,而k-dep[u]为子树的性质。所以可以把它分为两部分处理。一个节点如果被操作了tot次,那么第一部分为tot*dep[v] , 对于子树而言,为tot*∑dep[v]。同样第二部分,每个子节点都是k-dep[u],所以对于这棵子树为size*(k-dep[u]).

  然后就是线段树的长长代码.....还要多练啊。提速。注意一些细节,毕竟代码长了容易犯小错误,而且这样的小错是很难找到的。我运气还算比较好。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define maxn 50005
  6 #define ll long long 
  7 #define L(x) (x<<1)
  8 #define R(x) ((x<<1)|1)
  9 #ifdef WIN32
 10 #define AUTO "%I64d"
 11 #else 
 12 #define AUTO "%lld"
 13 #endif
 14 using namespace std;
 15 int n,q,ans,idx;
 16 int tot,ne[maxn*2],to[maxn*2],he[maxn],id[maxn]; 
 17 int xul[maxn],xur[maxn],depth[maxn];
 18 
 19 void add(int a,int b)
 20 {
 21     tot++;to[tot]=b;ne[tot]=he[a];he[a]=tot;
 22 }
 23 void dfs_xu(int x,int fa,int dep)
 24 {
 25     depth[x]=dep;
 26     xul[x]=++idx;//正序左 
 27     id[idx]=x;//反之 
 28     for (int i=he[x];i;i=ne[i])
 29     if (to[i]!=fa){
 30         dfs_xu(to[i],x,dep+1);
 31     }
 32     xur[x]=idx;//右端点 
 33 }
 34 /* /*-----------------xian_duan_shu-----------------------*/ 
 35 struct pp{
 36     ll dep,sum_tot,tot;//sum_tot: part_1
 37     ll cha,sum_cha,size;//sum_cha作为子树的sum,cha 作为单点的cha, 
 38 };
 39 pp tree[maxn*4];
 40 /*-------------add_dan----------------*/
 41 void add_tot(int x,ll val)
 42 {
 43     tree[x].tot+=val;
 44     tree[x].sum_tot+=val*tree[x].dep;
 45 }
 46 void add_cha(int x,ll val)
 47 {
 48     tree[x].cha+=val;
 49     tree[x].sum_cha+=val*tree[x].size;
 50 }
 51 /*-------------------pushdown--------------------*/
 52 void pushdown_tot(int cur)
 53 {
 54     if (!tree[cur].tot) return ;
 55     add_tot(L(cur),tree[cur].tot);
 56     add_tot(R(cur),tree[cur].tot);
 57     tree[cur].tot=0;
 58 }
 59 void pushdown_cha(int cur)
 60 {
 61     if(!tree[cur].cha) return ;
 62     add_cha(L(cur),tree[cur].cha);
 63     add_cha(R(cur),tree[cur].cha);
 64     tree[cur].cha=0;
 65 }
 66 /*----------------------uptate_sum---------------------*/
 67 void uptate_tot(int cur)
 68 {
 69     tree[cur].sum_tot=tree[L(cur)].sum_tot+tree[R(cur)].sum_tot;
 70 }
 71 void uptate_cha(int cur)
 72 {
 73     tree[cur].sum_cha=tree[L(cur)].sum_cha+tree[R(cur)].sum_cha;
 74 }
 75 /*-----------------------------opreate-------------------------------*/
 76 void change_tot(int cur,int l,int r,int x,int y,ll val)
 77 {
 78     if (l>=x&&r<=y)
 79     {
 80         add_tot(cur,val);
 81         return ;
 82     }
 83     pushdown_tot(cur);
 84     int mid=(l+r)>>1;
 85     if (x<=mid&&l<=y) change_tot(L(cur),l,mid,x,y,val);
 86     if (y>=mid+1&&x<=r) change_tot(R(cur),mid+1,r,x,y,val);
 87     uptate_tot(cur);
 88 }
 89 void change_cha(int cur,int l,int r,int x,int y,ll val)
 90 {
 91     if (l>=x&&r<=y)
 92     {
 93         add_cha(cur,val);
 94         return ;
 95     }
 96     pushdown_cha(cur);
 97     int mid=(l+r)>>1;
 98     if (x<=mid&&l<=y) change_cha(L(cur),l,mid,x,y,val);
 99     if (y>=mid+1&&x<=r) change_cha(R(cur),mid+1,r,x,y,val);
100     uptate_cha(cur);
101 }
102 ll query(int cur,int l,int r,int x,int y)
103 {
104     if (x<=l&&r<=y)
105         return tree[cur].sum_tot+tree[cur].sum_cha;
106     pushdown_tot(cur);pushdown_cha(cur);
107     int mid=(l+r)>>1;
108     ll an=0;
109     if (x<=mid&&l<=y) an+=query(L(cur),l,mid,x,y);
110     if (y>=mid+1&&x<=r) an+=query(R(cur),mid+1,r,x,y);
111     return an;
112 }
113 /*----------------------build-----------------------*/
114 
115 void update_build(int u)
116 {
117     tree[u].size=tree[L(u)].size+tree[R(u)].size;
118     tree[u].dep=tree[L(u)].dep+tree[R(u)].dep;//细节 
119 }
120 void build(int l,int r,int u)
121 {
122     if (l==r)
123     {
124         tree[u].dep=depth[id[l]];
125         tree[u].size=1;
126         return ;//****
127     }
128     int mid=(l+r)>>1;
129     build(l,mid,L(u));
130     build(mid+1,r,R(u));//mid+1
131     update_build(u);
132 }
133 /*-------------------------main----------------------------*/
134 int main()
135 {
136     freopen("c.in","r",stdin);
137     freopen("c.out","w",stdout);
138     cin>>n>>q;
139     for (int i=2;i<=n;i++)
140     {
141         int x;
142         scanf("%d",&x);
143         add(x,i);
144         add(i,x);
145     }
146     dfs_xu(1,0,1);
147     build(1,n,1);
148     while (q)
149     {
150         char c[2];int x;
151         scanf("%s",c);
152         if (c[0]=='A') {
153             int x;
154             ll y;
155             scanf("%d"AUTO,&x,&y);
156             change_tot(1,1,n,xul[x],xur[x],1);
157             change_cha(1,1,n,xul[x],xur[x],y-depth[x]);
158         }
159         else {
160             int x;
161             scanf("%d",&x);
162             ll ans=query(1,1,n,xul[x],xur[x]);
163             printf(AUTO,ans);
164             printf("
");
165         }
166         q--;
167     }
168     return 0;
169 }

 

   

  

原文地址:https://www.cnblogs.com/lx0319/p/6052284.html