「JOI 2017/2018 决赛」题解

LOJ 2347~2351
BZOJ上只有其中2道： 4273,4279

dp可以推个柿子把转移优化到$O\left(1\right)$$O(1)$，再套个wqs二分把状态数优化到$O\left(nlogn\right)$$O(nlogn)$

code：

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define ld long double
using namespace std;

{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 210000;
const ld eps = 1e-12;

int n,K;
int a[maxn],b[maxn],ti[maxn];

struct node
{
int k; ld x;
}f[maxn];
int dp(ld mid)
{
f[0]=(node){0,0.0};
int nown=0;
for(int i=1;i<=n;i++)
{
f[i].k=f[nown].k+1;
f[i].x=f[nown].x-b[nown]+(ld)a[i]+mid;
if(f[i].x-b[i]<f[nown].x-b[nown]) nown=i;
}
return f[n].k;
}

int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);

for(int i=0;i<=n;i++) a[i]=ti[i]+1,b[i]=ti[i+1];

ld l=-ti[n],r=ti[n];
while(r-l>eps)
{
ld mid=(l+r)/2.0;
int k=dp(mid);
if(k==K) { l=mid;break; }
if(k<K) r=mid;
else l=mid;
}
printf("%.0Lf\n",f[n].x-l*K);

return 0;
}

code：

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10ll)+=c-'0';
}
const int maxn = 510000;

int n;
struct node
{
ll a,b;
friend inline bool operator <(const node x,const node y){return x.a<y.a;}
}a[maxn];

int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);

scanf("%d",&n);
sort(a+1,a+n+1);

ll sum=0,pn=a[1].a,ans=0;
for(int i=1;i<=n;i++)
{
sum+=a[i].b;
ans=max(ans,pn-a[i].a+sum);
pn=max(pn,a[i+1].a-sum);
}
printf("%lld\n",ans);

return 0;
}

code：

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void up(int &a,const int &b){if(a<b)a=b;}
const int maxn =  3100;

int n,m,ans;
int a[maxn][maxn];
int Matchl(int i,int j)
{
return a[i][j-1]==0&&a[i][j]==1&&a[i][j+1]==2;
}
int Matchc(int i,int j)
{
return a[i-1][j]==0&&a[i][j]==1&&a[i+1][j]==2;
}
int f[2][3];

char str[maxn];

int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);

memset(a,-1,sizeof a);

scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",str+1);
for(int j=1;j<=m;j++) a[i][j]=str[j]=='R'?0:(str[j]=='G'?1:2);
}

int ans=0;
for(int s=2;s<=n+m;s++)
{
memset(f,0,sizeof f); int now=0;
for(int j=max(1,s-n);j<=m&&j+1<=s;j++)
{
int i=s-j;
now=!now;
for(int l=0;l<3;l++)
{
int &temp=f[!now][l];
up(f[now][0],temp);
if(l!=2&&Matchl(i,j)) up(f[now][1],temp+1);
if(l!=1&&Matchc(i,j)) up(f[now][2],temp+1);
temp=0;
}
}
up(f[now][0],f[now][1]);
up(f[now][0],f[now][2]);
ans+=f[now][0];
}
printf("%d\n",ans);

return 0;
}

code：

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 210000;
const int maxm = 410000;

ll ans;
int n,m,S,T,U,V;
int e[maxm][3],ec[maxm];
struct Graph
{
struct edge{int y,c,i,nex;}a[maxm]; int len,fir[maxn];
inline void ins(const int x,const int y,const int c,const int i)
{
a[++len]=(edge){y,c,i,fir[x]};fir[x]=len;
}

struct node
{
ll x; int i;
friend inline bool operator <(const node &x,const node &y){return x.x>y.x;}
}; priority_queue<node>q;

ll dis1[maxn],dis2[maxn],d[maxn<<1];
void Dij(int st,ll dis[])
{
for(int i=1;i<=n;i++) dis[i]=LLONG_MAX;
dis[st]=0; q.push((node){0ll,st});
while(!q.empty())
{
const node now=q.top(); q.pop();
int x=now.i; if(dis[x]!=now.x) continue;
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(dis[y]>dis[x]+a[k].c)
dis[y]=dis[x]+a[k].c,q.push((node){dis[y],y});
}
}
void solve(int st,ll D,ll d1[],ll d2[])
{
for(int i=1;i<=m;i++) ec[i]=-1;
for(int x=1;x<=n;x++)
{
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(d1[x]<d1[y]&&d1[x]+a[k].c+d2[y]==D)
ec[a[k].i]=x<y;
}

for(int i=1;i<=n*3;i++) d[i]=LLONG_MAX;
d[U]=0; q.push((node){d[U],U});
while(!q.empty())
{
const node now=q.top(); q.pop();
int x=now.i; if(d[x]!=now.x) continue;
int use=(x-1)/n; x=(x-1)%n+1;

for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y)
{
if(use!=2&&ec[a[k].i]==(x<y))
{
if(d[y+n]>now.x) d[y+n]=now.x,q.push((node){d[y+n],y+n});
}
int nu=use==1?2:use;
if(d[y+nu*n]>now.x+a[k].c)
d[y+nu*n]=now.x+a[k].c,q.push((node){d[y+nu*n],y+nu*n});
}
}
for(int i=0;i<3;i++) ans=min(ans,d[i*n+V]);
}
}g;
void Solve()
{
ans=LLONG_MAX;
g.solve(S,g.dis1[T],g.dis1,g.dis2);
g.solve(T,g.dis2[S],g.dis2,g.dis1);
}

int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);

for(int i=1;i<=m;i++)
{
g.ins(x,y,c,i); g.ins(y,x,c,i);
e[i][0]=x,e[i][1]=y,e[i][2]=c;
}
g.Dij(S,g.dis1); g.Dij(T,g.dis2);

Solve();
printf("%lld\n",ans);

return 0;
}

code：

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define cal(x) __builtin_popcount(x)
using namespace std;

const int maxn = (1<<20)+20;

int n,m,al;
int s[maxn],f1[maxn],f0[maxn];

char str[maxn];

int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);

scanf("%d%d",&n,&m); al=1<<n;
scanf("%s",str);
for(int i=0;i<al;i++) f1[i]=f0[i]=s[i]=str[i]-'0';

for(int i=0;i<n;i++)
for(int t=1<<i,j=0;j<al;j++) if(!(j>>i&1))
{
f1[j+t]+=f1[j];
f0[j]+=f0[j+t];
}

while(m--)
{
scanf("%s",str);
int x=0,y=0,z=0;
for(int i=0;i<n;i++) str[n-i-1]=='1'?x|=1<<i:(str[n-i-1]=='0'?y|=1<<i:z|=1<<i);

int ans=0;
if(cal(x)<=6)
{
for(int i=x;;i=(i-1)&x)
{
(cal(x^i)&1)?ans-=f1[i|z]:ans+=f1[i|z];
if(!i) break;
}
}
else if(cal(y)<=6)
{
for(int i=y;;i=(i-1)&y)
{
(cal(i)&1)?ans-=f0[i|x]:ans+=f0[i|x];
if(!i) break;
}
}
else
{
for(int i=z;;i=(i-1)&z)
{
ans+=s[i|x];
if(!i) break;
}
}
printf("%d\n",ans);
}

return 0;
}