省选前的动态规划胡做

这是一个不知道为什么反正就是想写成汇总的东西,还整合了之前写的一些DP题

因为沙茶博主DP很菜(什么都很菜,只是DP尤其菜)又做题少,所以写了这样一个记录沙茶博主在省选退役前刷的DP题的东西

好像上一行两句没有什么因果关系

-------------------废话结束---------------------------

 前一阵的链接们:

虚树DP:SDOI 2011 消耗战 HNOI 2014 世界树

凸优化:八省联考2018 林克卡特树

决策单调性:NOI 2009 诗人小G

树形DP:CF1118F2 Tree Cutting 国家集训队 Crash的文明世界

乱七八糟的东西们:九省联考2018 CoaT(写的暴力) WC 2018 州区划分(并没搞太懂)  

----------------------------------------------------------

HAOI 2011 problem a

转化

注意每个人的分数区间不可相交,然后莫得了

 1 #include<map>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=100005,inf=1e9; 
 7 struct a
 8 {
 9     int ll,rr,val;
10 }mem[N];
11 int n,t1,t2,cnt,ans,va[N],maxi[4*N];
12 map<pair<int,int>,int> mp;
13 void Mini(int &x,int y)
14 {
15     if(x>y) x=y;
16 }
17 bool cmp(a x,a y)
18 {
19     return x.ll==y.ll?x.rr<y.rr:x.ll<y.ll;
20 }
21 void Count(int l,int r)
22 {
23     pair<int,int> pr=make_pair(l,r);
24     if(!mp.count(pr)) mp[pr]=++cnt;
25     int id=mp[pr]; va[id]++;
26     mem[id]=(a){l,r,va[id]};
27 }
28 void Change(int nde,int l,int r,int pos,int tsk)
29 {
30     if(l==r)
31         maxi[nde]=tsk; 
32     else
33     {
34         int mid=(l+r)>>1,ls=2*nde,rs=2*nde+1;
35         if(pos<=mid) Change(ls,l,mid,pos,tsk);
36         else Change(rs,mid+1,r,pos,tsk);
37         maxi[nde]=max(maxi[ls],maxi[rs]);
38     }
39 }
40 int Query(int nde,int l,int r,int ll,int rr)
41 {
42     if(l>rr||r<ll)
43         return -inf;
44     else if(l>=ll&&r<=rr)
45         return maxi[nde];
46     else
47     {
48         int mid=(l+r)>>1,ls=2*nde,rs=2*nde+1;
49         return max(Query(ls,l,mid,ll,rr),Query(rs,mid+1,r,ll,rr));
50     }
51 }
52 int main()
53 {
54     scanf("%d",&n);
55     for(int i=1;i<=n;i++)
56     {
57         scanf("%d%d",&t1,&t2);
58         if(t2+1>n-t1) continue;
59         Count(t2+1,n-t1);
60     }
61     for(int i=1;i<=cnt;i++)
62         Mini(mem[i].val,mem[i].rr-mem[i].ll+1);
63     sort(mem+1,mem+1+cnt,cmp);
64 //    for(int i=1;i<=cnt;i++) printf("%d %d %d\n",mem[i].ll,mem[i].rr,mem[i].val);
65     for(int i=1;i<=cnt;i++)
66     {
67         int qry=Query(1,0,n,0,mem[i].ll-1);
68         int newa=qry+mem[i].val;
69         Change(1,0,n,mem[i].rr,newa),ans=max(ans,newa);
70     }
71     printf("%d ",n-ans);
72     return 0;
73 }
View Code

NOI 2015 寿司晚宴

转化

互质归根结底是没有相同质因数,而每个数只可能有一个大于$\sqrt n$的质因数。搞出来每个数小于$\sqrt n$的质因数的状态和(是否有)大于$\sqrt n$的质因数,按后者从小到大排序,大于$\sqrt n$的质因数相同的一块DP(没有的每个单独DP)。然后基本莫得了,注意容斥掉两个人都没选的情况

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=510,M=260,all=255;
 6 const int pri[8]={2,3,5,7,11,13,17,19};
 7 long long n,mod,cnt,ans,dp[M][M],fir[M][M],sec[M][M];
 8 struct a
 9 {
10     int sta,hug;
11 }num[N];
12 bool cmp(a x,a y)
13 {
14     return x.hug==y.hug?x.sta<y.sta:x.hug<y.hug;
15 }
16 void Add(long long &x,long long y)
17 {
18     x+=y;
19     if(x>=mod) x-=mod;
20 }
21 void Pre()
22 {
23     for(int i=2;i<=n;i++)
24     {
25         int tmp=i;
26         for(int j=0;j<=7;j++)
27             if(tmp%pri[j]==0)
28             {
29                 num[i].sta|=1<<j;
30                 while(tmp%pri[j]==0) tmp/=pri[j];
31             }
32         num[i].hug=tmp;
33     }
34     sort(num+2,num+1+n,cmp),dp[0][0]=1;
35 }
36 int main()
37 {
38     scanf("%lld%lld",&n,&mod),Pre();
39     for(int i=2;i<=n;i++)
40     {
41         if(i==2||num[i].hug==1||num[i].hug!=num[i-1].hug)
42         {
43             for(int j=0;j<=all;j++)
44                 for(int k=0;k<=all;k++)
45                     fir[j][k]=sec[j][k]=dp[j][k];
46         }
47         for(int j=all;~j;j--)
48             for(int k=all;~k;k--)
49                 if(!(j&k))
50                 {
51                     if(!(k&num[i].sta)) Add(fir[j|num[i].sta][k],fir[j][k]);
52                     if(!(j&num[i].sta)) Add(sec[j][k|num[i].sta],sec[j][k]);
53                 }
54         if(i==n||num[i].hug==1||num[i].hug!=num[i+1].hug)
55         {
56             for(int j=all;~j;j--)
57                 for(int k=all;~k;k--)
58                     if(!(j&k)) dp[j][k]=(fir[j][k]+sec[j][k]-dp[j][k]+mod)%mod;
59         }
60     }
61     for(int i=0;i<=all;i++)
62         for(int j=0;j<=all;j++)
63             if(!(i&j)) Add(ans,dp[i][j]);
64     printf("%lld",ans);
65     return 0;
66 }
View Code

SCOI 2014 方伯伯的玉米田

分析

直接做看起来不可做,分析性质,发现每次一定是拔一个后缀。因为后面比它高的拔了不会使答案变劣,后面不比它高的拔了还是没贡献,最后还拔走就行。

于是可以设计一个DP:$dp[i][j]$

猜你喜欢

转载自www.cnblogs.com/ydnhaha/p/10485568.html