多校联合第三场

1003 The Goddess Of The Moon
题意:如果字符串存在某个前缀与另一个字符串的后缀相同,则这两个字符串匹配,求n种字符串连成m个字符串的连接方式。
dp[i][j]= <k,j>dp[i1][k] ,dp[i][j]是指前i个串中第i个串为j的连接方式。
该dp表达式可以通过矩阵加速来实现

#include <iostream>
#include <cstdio>
#include <set>
#include<string.h>
#include <cstdlib>
#include<algorithm>
#include<math.h>
#include<vector>
using namespace std;

typedef long long ll;
const ll mod=1000000007;
# define N 100010

const ll maxn = 100;
ll t,n,m,a[maxn],ans,cnt;

bool connect(ll a,ll b){
    ll x[50],y[50],l1=0,l2=0;
    while(a) { x[l1++]=a%10,a/=10; }
    while(b) { y[l2++]=b%10,b/=10; }
    ll l=min(l1,l2),tmp=0;
    for(ll i=1;i<=l;i++){
        bool flag=true;
        for(ll j=0;j<i;j++){
            if(x[j]!=y[l2-i+j]) { flag=false; break; }
        }
        if(flag) tmp=i;
    }
    if(tmp>=2) return true;
    return false;
}

struct Mat{
    ll ma[60][60];
    void init() { memset(ma,0,sizeof(ma)); }
};

Mat A,B;

Mat operator * (const Mat &a,const Mat &b){
    Mat c; c.init();
    for(ll i=0;i<n;i++){
        for(ll j=0;j<n;j++){
            for(ll k=0;k<n;k++){
                c.ma[i][j]=(c.ma[i][j]+(a.ma[i][k]*b.ma[k][j])%mod)%mod;
            }
        }
    }
    return c;
}

Mat quick(Mat a,int b){
    Mat ans;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(i==j) ans.ma[i][j]=1;
            else ans.ma[i][j]=0;
        }
    }
    while(b){
        if(b&1) { ans=ans*a; b--; }
        a=a*a,b>>=1;
    }
    return ans;
}

int main(){
    //freopen("a.txt","r",stdin);
    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld",&n,&m);
        for(ll i=0;i<n;i++) scanf("%lld",&a[i]);
        sort(a,a+n); cnt=0;
        for(ll i=0;i<n;i++){
            if(i<n-1&&a[i]!=a[i+1]) a[cnt++]=a[i];
        }
        a[cnt++]=a[n-1]; n=cnt;
        A.init(),B.init();
        for(ll i=0;i<n;i++){
            for(ll j=0;j<n;j++){
                if(connect(a[i],a[j])) B.ma[j][i]=1;
            }
        }
        for(ll i=0;i<n;i++) A.ma[i][0]=1;
        B=quick(B,m-1);
        A=B*A;
        ans=0;
        for(ll i=0;i<n;i++) ans=(ans+A.ma[i][0])%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

1005 Fan Li
题意:求n个数中gcd相同的不相交区间的最大数量与对应的方 案数量
解法:
1.n个区间的最大不相交数量
解法:贪心。按区间结尾从小到大排序,取出第一个,然后取出满足条件的最小的第二个,以此类推即可。
拓展:求n个区间中必须选取k个区间的最大不相交数量
解法:同上,只不过先记录选取的k个区间的位置,在判断时必须满足区间不语这k个区间相交,相当于把区间分成了k+1份,分别进行贪心。

本题中先预处理出所有以第r个元素结尾gcd为x的连续区间,由于以第r个元素结尾的不同gcd个数之多为log(a[r]),因为以第r个元素结尾的区间gcd之间是约数关系,因此每次至少变化一个素因子p,a[r]至多log(a[r])个之因子,因此最多变化log(a[r])次。
设(l,r,x,pre)表示以第r个元素结尾gcd为x的区间左端点为pre,右端点为l
将上述信息存储在一个数组中,最多n*logn个四元组。
将上述四元组按照x大小排序,再按r大小排序。对于x相等的区间我们进行求解。
1.求最大不相交区间数量,由1中分析,可以贪心得到,但是求解方案数不能贪心,只能通过dp来求解。
设dp[i]:包含以第i个元素结尾的区间且gcd为x的最大不相交区间数量
sum[i]:前i个元素gcd为x的最大不相交区间数量
dp的求解过程可以通过贪心得到。首先如果dp[i]不递增,那么dp[i+1]不可能通过dp[i]得到,反证法:如果dp[i+1]通过dp[i]得到,说明r[i]< l[i+1],此时由于dp[i]不满足右端点小于i+1的左端点的最大dp值,因此不能作为dp[i+1]的转移值。所以只要记录下递增的dp值下标,然后每次更新dp时,只要二分查找满足r[j]<=l[i+1]的最大dp值,即最大r值即可作为dp[i+1]的最优转移值
再求sum[i]
sum[i]=i1j=1(l[i]pre[i]+1)sum[j](j<pre)+(lj)sum[j](j>=pre)(j<=l)
按照sum[j]对sum[i]的贡献可以求完每个sum[j]后维护两个树状数组求sum[j]的前n项和以及j*sum[j]的前n项和,

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<math.h>
#define Mod mod
using namespace std;

const int maxn = 100000+10;
int n,a[maxn];
const int mod = 998244353;

int gcd(int a,int b) { return b==0?a:gcd(b,a%b); }

struct no{
    int l,r,x,pre;
    bool operator<(const no &rhs)const{
        if(x!=rhs.x) return x<rhs.x;
        return r<rhs.r;
    }
}q[maxn<<6];
int tot,nxt[maxn<<1];
int ans1,ans2;
int vt[maxn<<6],top;
int dp[maxn<<1],sum[maxn<<1];

int node[2][maxn];
int low(int x) { return x&(-x); }
int query(int id,int x) { int ans=0; for(int i=x;i>=1;i-=low(i)) ans=((ans+node[id][i])%mod+mod)%mod; return ans; }
void update(int id,int x,int p) { for(int i=x;i<=n;i+=low(i)) node[id][i]=((node[id][i]+p)%mod+mod)%mod; }

int bi(int l,int r,int a,int b){
    int ret=-1;
    while(l<=r){
        int m=(l+r)>>1;
        if(vt[m]<b) l=m+1;
        else if(dp[vt[m]]>=a) ret=m,r=m-1;
        else l=m+1;
    }
    return ret;
}

void fenjie(){
    tot=0; int val[maxn];
    q[tot++]=(no) { 1,1,a[1],1 };
    nxt[1]=1,val[1]=a[1];
    for(int i=2;i<=n;i++){
        nxt[i]=i,val[i]=a[i];
        int pos=i;
        while(pos>0){
            val[pos]=gcd(val[pos],a[i]);
            while(nxt[pos]>1&&gcd(val[nxt[pos]-1],val[pos])==val[pos]){
                nxt[pos]=nxt[nxt[pos]-1];
            }
            q[tot++]=(no){ pos,i,val[pos],nxt[pos] };
            pos=nxt[pos]-1;
        }
    }
    sort(q,q+tot);
}

void solve(){
    ans1=ans2=0;
    for(int i = 0;i < tot; i++) {
        int top = 0;
        int j = i;
        while(j < tot && q[j].x == q[i].x) {
            int pos = 0;
            if(top > 0) {
                pos = lower_bound(vt+1, vt+top+1, q[j].l)-vt;
                pos--;
            }
            if(pos == 0) {
                dp[q[j].r] = 1;
                sum[q[j].r] = q[j].l-q[j].pre+1;
                if(!top || dp[vt[top]] <= 1) {
                    vt[++top] = q[j].r;
                    update(0, q[j].r, sum[q[j].r]);
                    update(1, q[j].r, 1ll*sum[q[j].r]*q[j].r%Mod);
                }
            } else {
                int mx = dp[vt[pos]];
                dp[q[j].r] = dp[vt[pos]]+1;
                sum[q[j].r] = 0;
                int pos2 = bi(1, pos, mx, q[j].pre);
                int pos3 = bi(1, pos, mx, 1);
                if(pos2 != -1) {
                    int add = 1ll*q[j].l*(query(0, vt[pos])-query(0, vt[pos2]-1))%Mod;
                    if(add < 0) add += Mod;
                    add -= (query(1, vt[pos])-query(1, vt[pos2]-1)+Mod)%Mod;
                    if(add < 0) add += Mod;
                    sum[q[j].r] = add;
                    sum[q[j].r] += 1ll*(q[j].l-q[j].pre+1)*(query(0, vt[pos2]-1)-query(0, vt[pos3]-1)+Mod)%Mod;
                    if(sum[q[j].r] >= Mod) sum[q[j].r] -= Mod;
                } else {
                    sum[q[j].r] += 1ll*(q[j].l-q[j].pre+1)*(query(0, vt[pos])-query(0, vt[pos3]-1)+Mod)%Mod;
                    if(sum[q[j].r] >= Mod) sum[q[j].r] -= Mod;
                }
                if(dp[vt[top]] <= dp[q[j].r]) {
                    vt[++top] = q[j].r;
                    update(0, q[j].r, sum[q[j].r]);
                    update(1, q[j].r, 1ll*sum[q[j].r]*q[j].r%Mod);
                }
            }
            if(dp[q[j].r] > ans1) {
                ans1 = dp[q[j].r];
                ans2 = sum[q[j].r];
            } else if(dp[q[j].r] == ans1) {
                ans2 += sum[q[j].r];
                if(ans2 >= Mod) ans2 -= Mod;
            }
            j++;
        }
        while(i < j) {
            int x = q[i].r;
            while(x <= n) {
                node[0][x] = node[1][x] = 0;
                x += x&-x;
            }
            i++;
        }
        i--;
    }
    printf("%d %d\n", ans1, ans2);
}

int main(){
    //freopen("a.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        fenjie();
        solve();
    }
    return 0;
}

1006 Beautiful Set
题意:给n个数的集合
1.Make the set become a sequence, the beautiful value of the sequence is the sum of all the interval’s gcd(greatest common divisor), and the beautiful value of the set is the sum of the beautiful value of all the possible sequence.
ans1= nk=11<=i1<i2<...<ik<=ngcd(ai1,,ai2...,aik)k!(nk)!(nk+1)
意思是选取k个数排列后插入原n-k个数的排列中有n-k+1种插入方法
按照gcd的值进行重新计算: gcd(ai1,,ai2...,aik)=d
ans1= nd=1dni=1f[i,d]k!(nk)!(nk+1) ,f[i,d]是从n个数中抽取i个数gcd为d的集合个数.

如果没有后面的 k!(nk)!(nk+1) ,那么 ni=1f[i,d] 的值是n个数中任取若干数gcd为d的集合个数,设为g[d]。可以先求G[d]:gcd为d的倍数的集合个数,这个可以在O(n*logn)时间内求出,再求g[d]=G[d]- idg[i] ,通过枚举i的倍数可以在O(n*logn)时间内求出g[1]…g[n],$\sum_{d=1}^nd*g[d]即为答案,总复杂度为O(n*logn)

回到原题
设h[i]= k!(nk)!(nk+1)
ans1= nk=11<=i1<i2<...<ik<=ngcd(ai1,,ai2...,aik)h[i]
= nd=1dni=1f[i,d]h[i]
我们可以考虑对d的贡献角度考虑,用F[i,d]表示从n个数中抽取i个数gcd为d的倍数的集合个数,设G[d]= ni=1F[i,d]h[i] ,那么g[d]同样等于G[d]- idg[i] 。设gcd是d的倍数的个数为beinum[d],F[i,d]中的i每次只枚举到beinum[d],又beinum[d]在1-maxn上求和复杂度是O(maxn*logmaxn),又求g[i]也是类似复杂度,所以从复杂度仍未O(n*logn)

2.For k from 1 to n, choose k numbers of the set, and calculate the gcd of the k numbers. The beautiful value of the k numbers is k * (gcd of the k chosen numbers). The beautiful value of the set is the sum of all of the beautiful value of k numbers.
ans2= nk=11<=i1<i2<...<ik<=ngcd(ai1,,ai2...,aik)k
按照gcd的值进行计数,ans2= gcd(ai1,,ai2...,aik)=d
ans1= nd=1dni=1f[i,d]i
h[i]=i,计算方法同上,或者可以通过组合数公式化简上式后直接求和

总结:
nk=11<=i1<i2<...<ik<=ngcd(ai1,,ai2...,aik)h[k] 可以在O(n*logn)复杂度内求出

#include <iostream>
#include <cstdio>
#include <set>
#include<string.h>
#include <cstdlib>
#include<algorithm>
#include<math.h>
#include<vector>
using namespace std;

typedef long long ll;
const ll mod=258280327;
# define N 100010

const int maxn = 100000+10;
ll maxx;
ll fac[maxn],inv[maxn];
ll n,a[maxn],num[maxn],beinum[maxn],G1[maxn],G2[maxn],ans1,ans2;
vector<ll> fact[maxn];

ll quick(ll a,ll b){
    ll ret=1;
    while(b){
        if(b&1) { ret=(ret*a)%mod; b--; }
        a=(a*a)%mod,b>>=1;
    }
    return ret;
}

ll Inv(ll x){
    return quick(x,mod-2);
}

void init(){
    fac[0]=1,inv[0]=1;
    for(int i=1;i<=maxn-5;i++){
        fac[i]=(fac[i-1]*i)%mod; inv[i]=Inv(fac[i]);
        fact[i].clear();
        for(int j=1;j*j<=i;j++){
            if(i%j==0){
                fact[i].push_back(j);
                if(i/j!=j) fact[i].push_back(i/j);
            }
        }
    }
}

int main(){
    //freopen("a.txt","r",stdin);
    init();
    while(scanf("%lld",&n)!=EOF){
        memset(num,0,sizeof(num));
        maxx=0;
        for(ll i=1;i<=n;i++) { scanf("%lld",&a[i]); num[a[i]]++; maxx=max(maxx,a[i]); }
        for(ll i=1;i<=maxx;i++){
            G1[i]=G2[i]=beinum[i]=0;
            for(int j=i;j<=maxx;j+=i) beinum[i]+=num[j];
            for(ll j=1;j<=beinum[i];j++){
                G1[i]=(G1[i]+(fac[beinum[i]]*inv[beinum[i]-j]%mod*fac[n-j+1]%mod))%mod;
            }
            if(beinum[i]>0) G2[i]=quick(2,beinum[i]-1)*beinum[i]%mod;
        }
        for(int i=maxx;i>=1;i--)
        for(ll i=maxx;i>=1;i--){
            for(int j=i;j<=maxx;j+=i){
                G1[i]=((G1[i]-G1[j])%mod+mod)%mod;
                G2[i]=((G2[i]-G2[j])%mod+mod)%mod;
            }
        }
        ans1=ans2=0;
        for(ll i=1;i<=maxx;i++) ans1=(ans1+G1[i]*i%mod)%mod,ans2=(ans2+G2[i]*i%mod)%mod;
        if(ans1<ans2) printf("Mr. Hdu %lld\n",ans2);
        else if(ans1>ans2) printf("Mr. Zstu %lld\n",ans1);
        else printf("Equal %lld\n",ans1);
    }
    return 0;
}

1007
题意:求1-n所有排列的value值。每个排列的value值定义如下:连接所有满足 i<ja[i]<a[j] 的数对,所有连通分量大小的乘积的平方。
dp[i]= ij=1C(i1,j1)(j1)!dp[ij](jj)
化简:dp[i]= ij=1(i1)!/(ij)!(jj)dp[ij]
法一:分离法
令k=i-j,dp[i]= i1k=0(i1)!/k!(ik)(ik)dp[k]
通过展开(i-k)*(i-k)可以将i和k分离,从而先求出sum[i],然后O(1)转移dp方程,从复杂度O(n)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 50001
#define ll long long
#define Mod mod
using namespace std;

const ll maxn = 100000+10;
const ll mod = 998244353;
ll n,dp[maxn];
ll fac[maxn],inv[maxn];

ll quick(ll a,ll b){
    ll ans=1;
    while(b) { if(b&1) ans=(ans*a)%mod; b>>=1,a=(a*a)%mod; }
    return ans;
}

void init(ll n){
    fac[0]=inv[0]=1;
    for(ll i=1;i<=n;i++) fac[i]=(fac[i-1]*i)%mod,inv[i]=quick(fac[i],mod-2);
    dp[0]=1,dp[1]=1;
    ll a=(dp[0]*inv[0]%mod+dp[1]*inv[1]%mod)%mod,b=dp[1]*inv[1]*2%mod,c=dp[1]*inv[1]%mod;
    for(ll i=2;i<=n;i++){
        dp[i]=(((i*i%mod*a%mod+c)%mod-i*b%mod)%mod+mod)%mod*fac[i-1]%mod;
        a=(a+dp[i]*inv[i]%mod)%mod;
        b=(b+dp[i]*inv[i]%mod*2*i%mod)%mod;
        c=(c+dp[i]*inv[i]%mod*i%mod*i%mod)%mod;
    }
}

int main(){
    init(100000);
    while(scanf("%lld",&n)!=EOF){
        printf("%lld\n",dp[n]);
    }
    return 0;
}

2.整体法,cdq分治+NTT——O(n*logn)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 50001
#define ll long long
#define Mod mod
using namespace std;

const ll maxn = 100000+10;
const ll mod = 998244353;
ll n,dp[maxn];
ll fac[maxn],inv[maxn];
ll a[maxn<<3],b[maxn<<3];
ll m1[maxn<<3],m2[maxn<<3],Top;

ll quick(ll a,ll b){
    ll ans=1;
    while(b) { if(b&1) ans=(ans*a)%mod; b>>=1,a=(a*a)%mod; }
    return ans;
}

void NTT(ll a[],ll n,ll rev){
    for(ll i=1,j=0;i<n;i++){
        for(ll k=n>>1;k>(j^=k);k>>=1);
        if(i<j) swap(a[i],a[j]);
    }
    for(ll i=0;i<n;i++) m2[i]=m1[i*(Top/n)];
    for(ll m=2;m<=n;m<<=1){
        ll wm=rev==1?n-n/m:n/m;
        for(ll i=0;i<n;i+=m){
            ll w=0;
            for(ll j=i;j<i+m/2;j++){
                ll t=m2[w]*a[j+m/2]%mod;
                a[j+m/2]=a[j]-t;
                if(a[j+m/2]<0) a[j+m/2]+=mod;
                a[j]=a[j]+t;
                if(a[j]>=mod) a[j]-=mod;
                w+=wm;
                if(w>=n) w-=n;
            }
        }
    }
    if(rev==-1){
        ll tmp=quick(n,mod-2);
        for(ll i=0;i<n;i++) a[i]=(a[i]*tmp)%mod;
    }
}

void solve(ll l,ll r){
    if(l==r) return;
    ll m=(l+r)>>1,len=(r-l+1),n=1;
    solve(l,m);
    while(n<=2*len) n<<=1;
    for(ll i=0;i<n;i++){
        a[i]=b[i]=0;
        if(i<n/2) b[i]=(i*i)%mod;
    }
    for(ll i=l;i<=m;i++) a[i-l+1]=(dp[i]*inv[i])%mod;
    NTT(a,n,1),NTT(b,n,1);
    for(ll i=0;i<n;i++) a[i]=(a[i]*b[i])%mod;
    NTT(a,n,-1);
    for(ll i=m+1;i<=r;i++) dp[i]=(dp[i]+a[i-l+1]*fac[i-1])%mod;
    solve(m+1,r);
}

void init(ll n){
    fac[0]=inv[0]=1;
    for(ll i=1;i<=n;i++) fac[i]=(fac[i-1]*i)%mod,inv[i]=quick(fac[i],mod-2);
    Top=1;
    while(Top<=2*n) Top<<=1;
    m1[0]=1,m1[1]=quick(3,(mod-1)/Top);
    for(ll i=2;i<Top;i++) m1[i]=(m1[i-1]*m1[1])%mod;
    dp[0]=1;
    solve(0,n);
}

int main(){
    init(100000);
    while(scanf("%lld",&n)!=EOF){
        printf("%lld\n",dp[n]);
    }
}

1009
题意:求让A数组递减,B数组递增的最长且字典序最小的下标数组
解法:分治法+线段树维护最大值
将序列分成前后两段,分别按A数组上升排序后,用尺取法求满足A值小于左边组第一个元素的右边组元素集合,然后在这些数中求得满足大于左边组第一个元素B值的最大dp值及最小下标,作为右边组元素对左边第一个元素的更新值,以此类推,用右边组序列更新左边组序列,更新复杂度O(n*logn),因此总复杂度为O(n*logn*logn)

//错误1:线段树起点搞错
//错误2:某个循环的终止条件搞错
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <time.h>
#include <assert.h>
#define MP make_pair
#define P pair<ll,ll>
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;

const ll maxn = 50000+10;
ll n,a[maxn],b[maxn];
vector<ll> aa,bb,answer;
ll idx[maxn];
ll dp[maxn],nxt[maxn];
P Max[maxn<<2];
ll ans,st;

bool cmp(ll x,ll y) { return a[x]<a[y]; }

void lisan(){
    sort(aa.begin(),aa.end()); sort(bb.begin(),bb.end());
    aa.erase(unique(aa.begin(),aa.end()),aa.end());
    bb.erase(unique(bb.begin(),bb.end()),bb.end());
    for(ll i=0;i<n;i++) { a[i]=lower_bound(aa.begin(),aa.end(),a[i])-aa.begin(); }
    for(ll i=0;i<n;i++) { b[i]=lower_bound(bb.begin(),bb.end(),b[i])-bb.begin(); }
}

void pushup(ll rt) { Max[rt]=max(Max[rt<<1],Max[rt<<1|1]); }

void build(ll l,ll r,ll rt){
    if(l==r) { Max[rt]=MP(0,-n); return; }
    ll m=(l+r)>>1;
    build(lson); build(rson);
    pushup(rt);
}

void update(ll p,P x,ll l,ll r,ll rt){
    if(l==r) { Max[rt]=max(Max[rt],x); return; }
    ll m=(l+r)>>1;
    if(p<=m) update(p,x,lson);
    else update(p,x,rson);
    pushup(rt);
}

void Copy(ll p,P x,ll l,ll r,ll rt){
    if(l==r) { Max[rt]=x; return; }
    ll m=(l+r)>>1;
    if(p<=m) Copy(p,x,lson);
    else Copy(p,x,rson);
    pushup(rt);
}

P query(ll L,ll R,ll l,ll r,ll rt){
    if(L<=l&&r<=R) return Max[rt];
    ll m=(l+r)>>1;
    P ret=MP(0,-n);
    if(L<=m) ret=max(ret,query(L,R,lson));
    if(R>m) ret=max(ret,query(L,R,rson));
    return ret;
}

void cdq(ll l,ll r){
    if(l==r) return;
    ll m=(l+r)>>1;
    cdq(m+1,r);
    for(ll i=l;i<=r;i++) idx[i]=i;
    sort(idx+l,idx+m+1,cmp); sort(idx+m+1,idx+r+1,cmp);
    for(ll i=l,j=m+1;i<=m;i++){//终止条件出错
        while(j<=r&&a[idx[j]]<=a[idx[i]]) update(b[idx[j]],MP(dp[idx[j]],-idx[j]),0,n,1),j++;
        P tmp=query(b[idx[i]],n,0,n,1);
        if((tmp.first+1>dp[idx[i]])||((tmp.first+1==dp[idx[i]])&&(-tmp.second<nxt[idx[i]]))){
            dp[idx[i]]=tmp.first+1,nxt[idx[i]]=-tmp.second;
        }
    }
    for(ll i=m+1;i<=r;i++) Copy(b[idx[i]],MP(0,-n),0,n,1);
    cdq(l,m);
}

int main(){
    //freopen("a.txt","r",stdin);
    while(scanf("%lld",&n)!=EOF){
        aa.clear(),bb.clear(),answer.clear();
        build(0,n,1);
        for(ll i=0;i<n;i++) { dp[i]=1,nxt[i]=n; scanf("%lld",&a[i]); aa.push_back(a[i]); }
        for(ll i=0;i<n;i++) { scanf("%lld",&b[i]); bb.push_back(b[i]); }
        lisan();
        cdq(0,n-1);
        ans=0,st=0;
        for(ll i=0;i<n;i++){
            if(ans<dp[i]) { ans=dp[i],st=i; }
        }
        printf("%lld\n",ans);
        for(ll i=st;i<n;i=nxt[i]) answer.push_back(i);
        for(ll i=0;i<answer.size();i++){
            if(i) printf(" ");
            printf("%lld",answer[i]+1);
        }
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值