10.06 联考题解

T1
场上会了 \(O(n^3)\) 的背包 DP。记 \(f_{j}\) 表示当前用了 \(j\) 元时最大的期望收益,枚举当前这个物品用 \(v\) 元钱,则 \(f_{j} \leftarrow f_{j-v}+\frac{v-l_i+1}{r_i-l_i+1}\times a_i\)。

设 \(k_i = \frac{a_i}{r_i-l_i+1}\),则原式等于 \(f_j\leftarrow f_{j-v} + (j-l_i+1)k_i\),发现 \(v\) 很讨厌,设 \(p=j-v\),则 \(p \in [j-r_i,j-l_i]\),式子等于 \(f_j\leftarrow f_p+(j-p-l_i+1)k_i\),把含有 \(p\) 的项放在一起则 \(f_j \leftarrow (j-l_i+1)k_i + f_p-p\times k_i\),令 \(g_p=f_p-p \times k_i\),则可以对此式做单调队列优化 DP,复杂度 \(O(Tnm)\)。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int T,n,m;
const int N = 1e4+10;
int l[N],r[N];
double a[N],f[N],g[N];
int q[N],hd,tl;
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>T;
    while(T--){
        bool flag=1;
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            cin>>l[i]>>r[i]>>a[i];
            flag&=(l[i]==r[i]);
        }
        for(int j=0;j<=m;j++){
            f[j]=0;
        }
        if(flag){
            for(int i=1;i<=n;i++){
                for(int j=m;j>=l[i];j--){
                    f[j]=max(f[j],f[j-l[i]]+a[i]);
                }
            }
            cout<<fixed<<setprecision(10)<<f[m]<<endl;
            continue;
        }
        for(int i=1;i<=n;i++){
            if(l[i]>m)continue;
            double k=a[i]/(r[i]-l[i]+1);
            for(int j=0;j<=m;j++){
                g[j]=f[j]-j*k;
            }
            hd=1,tl=0;
            for(int j=0;j<=m;j++){
                int p=j-l[i];
                if(p>=0){
                    while(hd<=tl&&g[q[tl]]<=g[p])tl--;
                    q[++tl]=p;
                }
                while(hd<=tl&&q[hd]<j-r[i])hd++;
                if(hd<=tl){
                    f[j]=max(f[j],g[q[hd]]+(j-l[i]+1)*k);
                }
            }
        }
        cout<<fixed<<setprecision(10)<<f[m]<<endl;
    }
    return 0;
}

T2
答案对 \(2\) 取模是一个突破口,启示我们寻找方案之间的对偶性,因为本质相同的两种方案不能贡献答案。

先把每个位置都填问号,然后依次考虑每个操作。

1.如果 \(x,y\) 都是问号,先考虑他们相异的情况,此时 \(x=1,y=0\) 和 \(x=0,y=1\) 是一致的,所以对答案没有影响,所以不用考虑。那就只要继续搜索他们相同的情况即可。

2.如果有一个是问号,另一个确定。不难发现任意一种情况都只会有一个后继搜索分支。

3.如果都是确定的,直接按题意进行。

问号的量级是 \(O(n)\) 的,决策只有 \(\frac{n}{2}\) 级别,所以时间复杂度是 \(O(2^{\frac{n}{2}}n^2)\)。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int n,m;
const int N = 1e3+10;
int a[N],b[N],p[N],t[N],ans[N];
void dfs(int k){
    if(k==m+1){
        int cnt=0;
        for(int i=1;i<=n;i++)cnt+=(p[i]==1);
        for(int i=1;i<=n;i++){
            int sum=0;
            for(int j=i;j<=n;j++){
                if(!p[j])break;
                sum+=(p[j]==1);
                if(sum==cnt)ans[j-i+1]^=1;
            }
        }
        return;
    }
    int x=a[k],y=b[k];
    if(p[x]==-1&&p[y]==-1){
        p[x]=p[y]=1;dfs(k+1);
        p[x]=p[y]=0;dfs(k+1);
        p[x]=p[y]=-1;
    }else if(p[x]==-1||p[y]==-1){
        if(p[x]==0||p[y]==1)dfs(k+1);
        else if(p[x]==1){p[x]=-1,p[y]=1;dfs(k+1);p[x]=1,p[y]=-1;}
        else if(p[y]==0){p[x]=0,p[y]=-1;dfs(k+1);p[x]=-1;p[y]=0;}
    }else{
        if(p[x]==1&&p[y]==0){
            p[x]=0,p[y]=1;dfs(k+1);p[x]=1;p[y]=0;
        }else{
            dfs(k+1);
        }
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>a[i]>>b[i];
    }
    memset(p,-1,sizeof(p));
    dfs(1);
    for(int i=1;i<=n;i++)cout<<ans[i]<<" ";
    return 0;
}

其余的先鸽了。

posted @ 2026-10-06 19:22  farenara_sayowell  阅读(8)  评论(0)    收藏  举报