acwing 智商药

发布时间 2023-07-04 21:52:38作者: zouyua

题目链接:5046. 智商药 - AcWing题库

首先考虑dfs

  不用想肯定超时 过了10/17个测试点

  代码

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef pair<int,int> PII;
 5 typedef long long ll;
 6 const int N=1e5+10,M=2*N;
 7 const int p=1e9+7;
 8 ll n,m;
 9 struct node
10 {
11     int l, r;
12 
13 }med[N];
14 bool st[N];
15 ll res=0;
16 void dfs(ll u)
17 {
18     if(u>n) return ;
19     //cout<<u<<endl;
20     if(u==n) 
21     {
22         res++;
23         return ;
24     }
25     for(int i=1;i<=m;i++)
26     {
27         if(!st[i]&&med[i].l<=u&&u<=med[i].r-1)
28         {
29             st[i]=true;
30             dfs(med[i].r);
31             st[i]=false;
32         }
33     }
34 }
35 void solve()
36 {
37     cin>>n>>m;
38     for(int i=1;i<=m;i++)
39         cin>>med[i].l>>med[i].r;
40     sort(med+1,med+1+m,[](struct node a,struct node b)->bool {return a.l==b.l?a.r<b.r:a.l<b.l;});
41     //for(int i=1;i<=m;i++) cout<<med[i].l<<' '<<med[i].r<<endl;
42     dfs(0);
43     cout<<res<<endl;
44 
45 }
46 int main()
47 {
48     int T = 1;
49     //cin >> T;
50     while(T --)
51     {
52         solve();
53     }
54     return 0;
55 }

然后考虑dp

  注意到n最大为1e9,肯定不能作为下标,m=1e5,可以考虑,f[i]的表示的集合为只用前i种药,且一定会吃第i种药,属性为集合中的方案数

  f[i]=sum(第i-1满足的条件之和) 因为吃药会变成med.r一定要按照r排序,也注意到第i-1满足条件的一定是一个区间,可以用树状数组,因为med.r为递增,也可以前缀和

  0为特殊的药(0,0),前缀和习惯从1开始,所以可以从2开始读入每条边,后排序,枚举每个药品,找到前面能吃到这个药l-1的区间左右端点,进行二分,在进行f的前缀区间累加

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 #define endl "\n";
 5 typedef pair<int,int> PII;
 6 typedef long long ll;
 7 const int N=1e5+10,M=2*N;
 8 const int p=1e9+7;
 9 ll n,m;
10 struct node
11 {
12     int l, r;
13 
14 }med[N];
15 ll f[N],s[N];
16 ll res;
17 int getl(int x)
18 {
19     int l=1,r=m+1;
20     while(l<r)
21     {
22         int mid=l+r>>1;
23         if(med[mid].r>=x) r=mid;
24         else l=mid+1; 
25     }
26     return l;
27 }
28 int getr(int x)
29 {
30     int l=1,r=m+1;
31     while(l<r)
32     {
33         int mid=l+r+1>>1;
34         if(med[mid].r<=x) l=mid;
35         else r=mid-1; 
36     }
37     return l;
38 }
39 void solve()
40 {
41     cin>>n>>m;
42     for(int i=2;i<=m+1;i++) cin>>med[i].l>>med[i].r;
43     sort(med+1,med+2+m,[](struct node a,struct node b)->bool {return a.r<b.r;});
44     //for(int i=1;i<=m;i++) cout<<med[i].l<<' '<<med[i].r<<endl;
45     f[1]=1,s[1]=1;
46     for(int i=2;i<=m+1;i++)
47     {
48         int l=getl(med[i].l),r=getr(med[i].r-1);
49         //s[i]=s[i-1];
50         f[i]=(s[r]-s[l-1])%p;
51         s[i]=(s[i-1]+f[i])%p;
52         if(med[i].r==n) res=(res+f[i])%p;
53     }
54     cout<<(res+p)%p<<endl;
55 }
56 int main()
57 {
58     ios::sync_with_stdio(false);
59     cin.tie(0);
60     int T = 1;
61     //cin >> T;
62     while(T --)
63     {
64         solve();
65     }
66     return 0;
67 }

  关闭流同步后运行时间447ms,之前是878ms,最后负数取模还是负数,可以+p后%p得到答案