2020.11.30~2020.12.6 做題記錄

P1552 [APIO2012]派遣(線段樹合併+二分)

線段樹合併板子題,維護子樹內薪水爲i的忍者有多少個,並記錄薪水的和。爲了使能被派遣的忍者更多,貪心取子樹內儘可能多的便宜忍者,線段樹上二分即可

直接線段樹合併可能會卡空間,離散化一下

線段樹合併的最後一層不能pushup!!!會變成0的,因此需要邊合併邊求和

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 100005
  6 #define M1 N1*50
  7 #define ll long long
  8 using namespace std;
  9 
 10 int n,S,tot,maxn;
 11 int real[N1];
 12 struct node{
 13     int id,val;
 14     bool operator < (const node &s2) const
 15     {
 16         if(val!=s2.val) return val<s2.val;
 17         return id<s2.id;
 18     }
 19 }a[N1];
 20 
 21 struct Edge{
 22 int to[N1],nxt[N1],head[N1],cte;
 23 void ae(int u,int v)
 24 {
 25     cte++; to[cte]=v, nxt[cte]=head[u];
 26     head[u]=cte;
 27 }
 28 }e;
 29 struct SEGTREE{
 30 int ls[M1],rs[M1],sum[M1],root[N1],cnt;
 31 ll cost[M1];
 32 void pushup(int rt)
 33 {
 34     sum[rt]=sum[ls[rt]]+sum[rs[rt]];
 35     cost[rt]=cost[ls[rt]]+cost[rs[rt]];
 36 }
 37 void upd(int x,int l,int r,int &rt,int w)
 38 {
 39     if(!rt) rt=++cnt;
 40     sum[rt]+=w, cost[rt]+=real[x]; 
 41     if(l==r) return; 
 42     // if(l==r) { sum[rt]+=w, cost[rt]+=x; return; }
 43     int mid=(l+r)>>1;
 44     if(x<=mid) upd(x,l,mid,ls[rt],w);
 45     else upd(x,mid+1,r,rs[rt],w);
 46     pushup(rt);
 47 }
 48 int mrg(int r1,int r2)
 49 {
 50     if(!r1||!r2) return r1+r2;
 51     int rt=++cnt;
 52     sum[rt]=sum[r1]+sum[r2];
 53     cost[rt]=cost[r1]+cost[r2];
 54     ls[rt]=mrg(ls[r1],ls[r2]);
 55     rs[rt]=mrg(rs[r1],rs[r2]);
 56     // pushup(rt);
 57     return rt;
 58 }
 59 ll query(ll res,int l,int r,int rt)
 60 {
 61     if(res>=cost[rt]) return sum[rt];
 62     if(l==r) return 0;
 63     int mid=(l+r)>>1;
 64     if(res>=cost[ls[rt]]) return sum[ls[rt]]+query(res-cost[ls[rt]],mid+1,r,rs[rt]);
 65     else return query(res,l,mid,ls[rt]);
 66 }
 67 }s;
 68 
 69 int fa[N1],sal[N1],lea[N1];
 70 
 71 ll dfs(int u)
 72 {
 73     int j,v; ll ans=0;
 74     s.upd(sal[u],1,maxn,s.root[u],1);
 75     for(j=e.head[u];j;j=e.nxt[j])
 76     {
 77         v=e.to[j]; if(v==fa[u]) continue;
 78         ans=max(ans,dfs(v));
 79         s.root[u]=s.mrg(s.root[u],s.root[v]);
 80      }
 81      ans=max(ans,1ll*lea[u]*s.query(tot,1,maxn,s.root[u]));
 82      return ans;
 83 }
 84 int main() 
 85 {
 86 //    freopen("a.txt","r",stdin);
 87     scanf("%d%d",&n,&tot);
 88     for(int i=1;i<=n;i++)
 89     {
 90         scanf("%d%d%d",&fa[i],&sal[i],&lea[i]);
 91         if(fa[i]) e.ae(fa[i],i);
 92         else S=i;
 93         a[i]=(node){i,sal[i]}; 
 94     }
 95     sort(a+1,a+n+1);
 96     maxn=1;
 97     for(int i=1;i<=n;i++)
 98     {
 99         if(a[i].val!=a[i-1].val) maxn++, real[maxn]=a[i].val;
100         sal[a[i].id]=maxn;
101     }
102     ll ans=dfs(S);
103     printf("%lld\n",ans);
104     return 0;
105 }
View Code

#273 DNA序列 (DP)

設計DP,f[i][j]表示第一個串匹配到第i位,第二個串匹配到j位時的最大匹配值

然而連續空格的負貢獻會減少,容易想到分三種情況討論,所以加一維記錄

f[i][j][0/1/2]分別表示兩個串分別匹配到i,j時,最後一個位置是 x x // x _ // _ x 時的答案 (x是字母,_是空格)

轉移方程很水,注意得賦初始值,但還不能直接memset,會T..

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define N1 3040
 6 #define inf 0x3f3f3f3f
 7 #define ll long long
 8 using namespace std;
 9 
10 char str1[N1],str2[N1];
11 int a[N1],b[N1],w[4][4],f[N1][N1][3];
12 int n,m,A,B;
13 int idx(char c)
14 {
15     if(c=='A') return 0;
16     if(c=='T') return 1;
17     if(c=='G') return 2;
18     if(c=='C') return 3;
19     return -1;
20 }
21 
22 int main() 
23 {
24 //    freopen("a.txt","r",stdin);
25     int i,j,k;
26     scanf("%s",str1+1); n=strlen(str1+1);
27     for(i=1;i<=n;i++) a[i]=idx(str1[i]);
28     scanf("%s",str2+1); m=strlen(str2+1);
29     for(i=1;i<=m;i++) b[i]=idx(str2[i]);
30     for(i=0;i<4;i++) for(j=0;j<4;j++) scanf("%d",&w[i][j]);
31     scanf("%d%d",&A,&B);
32     //memset(f,-0x3f,sizeof(f));
33     f[0][0][0]=0; f[0][0][1]=f[0][0][2]=-inf;
34     for(i=0;i<=n;i++) 
35     {
36         for(j=0;j<=m;j++)
37         {
38             if(!i&&!j) continue;
39             f[i][j][0]=f[i][j][1]=f[i][j][2]=-inf;
40             if(i>0 && j>0)
41             for(k=0;k<=2;k++) //x x
42                 f[i][j][0]=max(f[i][j][0], f[i-1][j-1][k]+w[a[i]][b[j]] );
43 
44             //x _
45             if(i>0)
46             {
47                 f[i][j][1]=max(f[i][j][1], f[i-1][j][0]-A );
48                 f[i][j][1]=max(f[i][j][1], f[i-1][j][1]-B );
49                 f[i][j][1]=max(f[i][j][1], f[i-1][j][2]-A );
50             }
51 
52             //_ x
53             if(j>0)
54             {
55                 f[i][j][2]=max(f[i][j][2], f[i][j-1][0]-A );
56                 f[i][j][2]=max(f[i][j][2], f[i][j-1][1]-A );
57                 f[i][j][2]=max(f[i][j][2], f[i][j-1][2]-B );
58             }
59         }
60     }
61     int ans=-inf;
62     ans=max(ans,f[n][m][0]); ans=max(ans,f[n][m][1]); ans=max(ans,f[n][m][2]);
63     printf("%d\n",ans);
64     return 0;
65 }
View Code

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章