csps模拟93序列,二叉搜索树,走路题解

题面:node

模拟93考得并不理想,二维偏序没看出来,然而看出来了也不会打ios

序列:数组

对a,b数列求前缀和,那么题意转化为了知足$suma[i]>=suma[j]$且$sumb[i]>=sumb[j]$的最大$i-j+1$值ide

那么就是二维偏序,那么按a排序,把b塞到树状数组里spa

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<ctime>
 8 #define int long long
 9 using namespace std;
10 const int MAXN=5e5+5;
11 int n,ans=0,sta[MAXN],top=0;
12 int read(){
13     int x=0,f=1;char ch=getchar();
14     while(ch<'0'||ch>'9'){
15         if(ch=='-') f=-1;
16         ch=getchar();
17     }
18     while(ch>='0'&&ch<='9'){
19         x=(x<<3)+(x<<1)+ch-'0';
20         ch=getchar();
21     }
22     return x*f;
23 }
24 struct node{
25     int a,b,id;
26     friend bool operator < (node p,node q){
27         return p.a==q.a?p.b<q.b:p.a<q.a;
28     }
29 }val[MAXN];
30 int lowbit(int x){
31     return x&-x;
32 }
33 int c[MAXN];
34 void update(int pos,int val){
35     for(int i=pos;i<=top;i+=lowbit(i)){
36         c[i]=min(c[i],val);
37     }
38 }
39 int query(int pos){
40     int res=0x3f3f3f3f3f3f3f3f;
41     for(int i=pos;i>0;i-=lowbit(i)){
42         res=min(res,c[i]);
43     }
44     return res;
45 }
46 signed main(){
47     n=read();
48     for(int i=1;i<=n;++i){
49         val[i].a=read();
50         val[i].a+=val[i-1].a;
51         val[i].id=i;
52     }
53     for(int i=1;i<=n;++i){
54         val[i].b=read();
55         val[i].b+=val[i-1].b;
56         sta[++top]=val[i].b;
57     }
58     sort(val+1,val+n+1);
59     sort(sta+1,sta+top+1);
60     top=unique(sta+1,sta+top+1)-sta-1;
61     for(int i=1;i<=n;++i)
62         val[i].b=lower_bound(sta+1,sta+top+1,val[i].b)-sta;
63     memset(c,0x3f,sizeof(c));
64     for(int i=1;i<=n;++i){
65         int res=query(val[i].b);
66         ans=max(ans,val[i].id-res);
67         update(val[i].b,val[i].id);
68     }
69     printf("%lld\n",ans);
70     return 0;
71 }
View Code

二叉搜索树:code

区间dp,设f[i,j]表示考虑区间[i,j]的贡献,则f[i,j]=min(f[i,k-1]+f[k+1,j]+a[i,j])blog

而后发现k有决策单调性,因此咱们记录一个dp数组,dp[i,j]表示f[i,j]是由那一个k转移而来,而后对于每个i,j,枚举k的范围就变成了dp[i+1,j]到dp[i,j-1]排序

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 #define int long long
 7 using namespace std;
 8 const int MAXN=5005;
 9 int n,ans=0,sum[MAXN],f[MAXN][MAXN],dp[MAXN][MAXN];
10 struct node{
11     int x,id;
12     friend bool operator < (node p,node q){
13         return p.x==q.x?p.id>q.id:p.x>q.x;
14     }
15 }a[MAXN];
16 int min(int p,int q){
17     return p<q?p:q;
18 }
19 signed main(){
20     memset(f,0x3f,sizeof(f));
21     scanf("%lld",&n);
22     for(int i=1;i<=n;++i){
23         scanf("%lld",&a[i].x);
24         a[i].id=i;
25         sum[i]=sum[i-1]+a[i].x;
26         f[i][i]=a[i].x;
27         dp[i][i]=i;
28     }
29     for(int i=0;i<=n+1;++i){
30         for(int j=0;j<i;++j) f[i][j]=0;
31     }
32     for(int l=2;l<=n;++l){
33         for(int i=1;i+l-1<=n;++i){
34             int j=i+l-1;
35             for(int k=dp[i][j-1];k<=dp[i+1][j];++k){
36                 if(f[i][j]>=f[i][k-1]+f[k+1][j]+sum[j]-sum[i-1]){
37                     f[i][j]=f[i][k-1]+f[k+1][j]+sum[j]-sum[i-1];
38                     dp[i][j]=k;
39                 }
40             }
41         }
42     }
43     printf("%lld\n",f[1][n]);
44     return 0;
45 }
View Code

走路:分治消元get

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define int long long
 6 using namespace std;
 7 const int MAXM=1e5+5,mod=998244353;
 8 int n,m,du[305],cnt[305][305],inv[MAXM],a[305][305],ans[305];
 9 int q_pow(int a,int b,int p){
10     int res=1;
11     while(b){
12         if(b&1) res=res*a%p;
13         a=a*a%p;
14         b>>=1;
15     }
16     return res;
17 }
18 void solve(int l,int r){
19     if(l==r){
20         ans[l]=(a[1][n+1]+mod)%mod;
21         return ;
22     }
23     int t[305][305];
24     for(int i=1;i<=n;++i){
25         for(int j=1;j<=n+1;++j)
26             t[i][j]=a[i][j];
27     }
28     int mid=(l+r)>>1;
29     for(int x=mid+1;x<=r;++x){
30         int invv=q_pow(a[x][x],mod-2,mod);
31         for(int i=1;i<=n+1;++i) (a[x][i]*=invv)%=mod;
32         for(int i=1;i<=n;++i){
33             if(i==x) continue;
34             invv=a[i][x];
35             for(int j=l;j<=r;++j){
36                 a[i][j]=(a[i][j]-a[x][j]*invv+mod)%mod;
37             }
38             a[i][n+1]=(a[i][n+1]-a[x][n+1]*invv+mod)%mod;
39         }
40     }
41     solve(l,mid);
42     for(int i=1;i<=n;++i){
43         for(int j=1;j<=n+1;++j)
44             a[i][j]=t[i][j];
45     }
46     for(int x=l;x<=mid;++x){
47         int invv=q_pow(a[x][x],mod-2,mod);
48         for(int i=1;i<=n+1;++i) (a[x][i]*=invv)%=mod;
49         for(int i=1;i<=n;++i){
50             if(i==x) continue;
51             invv=a[i][x];
52             for(int j=l;j<=r;++j){
53                 a[i][j]=(a[i][j]-a[x][j]*invv%mod+mod)%mod;
54             }
55             a[i][n+1]=(a[i][n+1]-a[x][n+1]*invv%mod+mod)%mod;
56         }
57     }
58     solve(mid+1,r);
59 }
60 signed main(){
61     scanf("%lld%lld",&n,&m);
62     for(int i=1,u,v;i<=m;++i){
63         scanf("%lld%lld",&u,&v);
64         ++du[u],++cnt[u][v];
65     }
66     for(int i=1;i<=m;++i) inv[i]=q_pow(i,mod-2,mod);
67     for(int i=1;i<=n;++i){
68         for(int j=1;j<=n;++j){
69             a[i][j]=cnt[i][j]*q_pow(du[i],mod-2,mod)%mod;
70         }
71         a[i][n+1]=-1;
72         --a[i][i];
73     }
74     solve(1,n);
75     for(int i=2;i<=n;++i) printf("%lld\n",ans[i]);
76     return 0;
77 }
View Code