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;
}
其余的先鸽了。

浙公网安备 33010602011771号