ICPC Premade Contest 4
赛后补题
D
类似求
#include<bits/stdc++.h>
using namespace std;
#define db double
const db inf = 1e9;
const db eps = 1e-10;
const int N = 3009;
int n,kk,head[N],tot,siz[N];
struct pp{int nxt,to;}g[N<<1];
db s[N],p[N],a[N];
void add(int u,int v){g[++tot].nxt=head[u],g[tot].to=v,head[u]=tot;}
db f[N][N];int flag;
void dfs(int u){
if(u) siz[u]=1,f[u][1]=a[u];
if(u==0) f[u][0]=0,siz[u]=0;
for(int i=head[u];i!=-1;i=g[i].nxt){
int v=g[i].to;dfs(v);
for(int j=siz[u];j>=0;j--){
for(int k=siz[v];k>=1;k--)
if(f[u][j]>-1e8&&f[v][k]>-1e8) f[u][j+k]=max(f[u][j+k],f[u][j]+f[v][k]);
}
siz[u]+=siz[v];
}
f[u][0]=0;
return ;
}
bool check(){
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++) f[i][j]=-inf;
dfs(0);
return f[0][kk]>-eps;
}
int main(){
memset(head,-1,sizeof(head));tot=0;
scanf("%d%d",&kk,&n);
for(int i=1;i<=n;i++){
int u;scanf("%lf%lf%d",&p[i],&s[i],&u);add(u,i);
}
db l=0,r=1e5,ans;
while(r>=l+eps){
db mid=(l+r)/2;
for(int i=1;i<=n;i++) a[i]=s[i]-mid*p[i];
if(check()) l=mid,ans=mid;
else r=mid;
}
for(int i=1;i<=n;i++) a[i]=s[i]-ans*p[i];
check();
if(abs(f[0][kk])>0.1) throw;
printf("%.3lf\n",round(ans*1000)/1000);
return 0;
}
//若干组数对各自和之商=0,1分数规划=二分答案=ai-L*bi权值定,求符合条件下的和的max,看最大>0否
E
对任意 k 求
显然,对每个 k 都求,卷积板题,差变和,把其中一个数组反过来就好了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define db double
const db Pi = acos(-1);
const int N = 3e6+9;
int n,m,tr[N];
char s[N];
struct CP{
db x,y;
CP(db x=0,db y=0):x(x),y(y){}
CP operator+(const CP &a){return CP(x+a.x,y+a.y);}
CP operator-(const CP &a){return CP(x-a.x,y-a.y);}
CP operator*(const CP &a){return CP(x*a.x-y*a.y,x*a.y+y*a.x);}
}f[N],p[N];
void fft(CP *F,int nn,int flag){
for(int i=0;i<nn;i++) if(i<tr[i]) swap(F[i],F[tr[i]]);
for(int p=2;p<=nn;p<<=1){
CP tG(cos(2*Pi/p),sin(2*Pi/p));
if(!flag) tG.y*=-1;
int len=p>>1;
for(int j=0;j<nn;j+=p){
CP buf(1,0);
for(int k=j;k<j+len;k++){
CP tt=buf*F[k+len];
F[k+len]=F[k]-tt;
F[k]=F[k]+tt;
buf=buf*tG;
}
}
}
return ;
}
ll ans[N];
int main(){
scanf("%s",s);n=strlen(s);
for(int i=0;i<n;i++)
if(s[i]=='A') f[i].x=1;
else p[n-i-1].x=1;
m=1;while(m<n*2) m*=2;
for(int i=0;i<m;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?(m>>1):0);
fft(f,m,1);fft(p,m,1);
for(int i=0;i<m;i++) f[i]=f[i]*p[i];
fft(f,m,0);
for(int i=0;i<m;i++) ans[i]=(ll)(f[i].x/(db)m+0.49);
for(int i=0;i<n-1;i++) printf("%lld\n",ans[n+i]);
return 0;
}
/*
你 TM ,我知道为啥是n+i了,
因为你k是负时才是 B ... A啊!!!
f[i-j]=\sum B[i]*A[j]
f[k]=\sum B[k+j]*A[j]
B'[n-k-j]=B[k+j]
f'[n-k]=f[k]
f'[n-k]=\sum B'[n-k-j]*A[j]
f[k]=\sum B'[n-k-j]*A[j]
//看到你要求0~n的所有值,差不多卷积了,特别是答案的项数有和/差的关系
*/
H
背包,
背包能有什么好做法啊,按性价比贪心不太科学(真要能贪还要背包做啥),只能在常规 dp 上发现性质优化。
显然是按每个体积分类做背包,同体积按权值从大到小排序,先选大的一定更优,所以同体积下一定是凸的。
dp 有这个贪心策略就说明在决策上是可以优化的,想想可否决策单调性。(或者是对下标模某个数同余下有单调性)
若决策有单调性,可以试试分治转移,或者斜率优化。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e6+9;
const int M = 309;
int n,k;
vector<int >v[M];
vector<ll >sum[M];
ll f[N],g[N];
bool cmp(int x,int y){return x>y;}
void solve(int q,int p,int l,int r,int a,int b){
if(r<l) return ;
int mid=(l+r)>>1,id=a;//f[q+p*mid]
ll t=-1;
for(int i=a;i<=min(mid-1,b);i++)
if(mid-i<=v[p].size()&&t<f[q+p*i]+sum[p][mid-i]){
t=f[q+p*i]+sum[p][mid-i];
id=i;
}
if(f[q+p*mid]>t){t=max(t,f[q+p*mid]);id=mid;}
solve(q,p,l,mid-1,a,id);
solve(q,p,mid+1,r,id,b);
g[q+p*mid]=t;
return ;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
int s,val;scanf("%d%d",&s,&val);
v[s].push_back(val);
}
for(int i=1;i<=300;i++) sort(v[i].begin(),v[i].end(),cmp);
for(int i=1;i<=300;i++){
sum[i].push_back(0);
ll x=0;
for(int j=1;j<=v[i].size();j++){
x+=v[i][j-1];
sum[i].push_back(x);
}
}
memset(f,-0x3f,sizeof(f));
f[0]=0;
for(int i=1;i<=300;i++){
for(int j=0;j<i;j++){
solve(j,i,0,(k-j)/i,0,(k-j)/i);
for(int t=j;t<=k;t+=i) f[t]=g[t];
}
}
ll ans=0;
for(int i=1;i<=k;i++){
ans=max(ans,f[i]);
printf("%lld ",ans);
}
puts("");
return 0;
}
/*
f[i]=f[j]+w_{i-j}
证明 若 j >k ,f[i+1]=f[j]+w_{i+1-j}>f[i+1]=f[k]+w_{i+1-k}
对比 f[i+1]=f[j+1]+w_{i-j} 这是跟 f[i]=f[j]+...同样的选择的
f[i+1]=f[j]+w_{i+1-j}
f[i+1]=f[j-1]+w_{i+2-j} 如果3式大于2式,那么意味着在 f[i] 处时应该多选择 w 中比 i-j 更小的那一项
而不是保留之前的项(感受到包含劣于相交就使,实在不行打表决策点!!感受到凸等性质直接决策单调性)
故决策单调性成立,使用分治
同时这是对于同一模下同余项
决策单调性与直接单调队列区别,
就是决策点虽然是单增的,但你怎么找到这个决策点,每个点转移过来的 dp 值可不一定单峰
所以还是分治加决策单调。
*/
A
据说是 meet in the middle ,线索是
B
据说是先建括号树,从后往前做
J
扫描线
K
点分+李超树/凸包
G
好像是个