csp-s模拟测试98「装饰·午餐」
装饰
题解
其实是挺好的一道题
正着实在不好做,还要考虑当前点是否可以传递,
可以提前把整个链都处理出来,例如第一秒点灯把整条链都染上色
然而你不知道终止时间
枚举终止时间即可
算是时光倒流
还有,感谢wwb_ape
代码
#include<bits/stdc++.h> using namespace std; #define ll long long #define A 111 ll sta[A],light[A],qw[A],fa[A],ff[35][35],f[35][1<<17|1]; ll vis[20]; ll n,ans=0x3f3f3f3f,top,mudi; int main(){ freopen("decoration.in","r",stdin); freopen("decoration.out","w",stdout); scanf("%lld",&n); for(ll i=2;i<=n;i++) scanf("%lld",&fa[i]); for(ll i=1;i<=n;i++){ scanf("%lld",&qw[i]); if(qw[i]==1) mudi|=1<<(i-1); } ll maxn=(1<<n)-1; fa[1]=0; for(ll i=1;i<=32;i++){ for(ll j=1;j<=n;j++){ ll cnt=0,now=j,tot=n-i; while(cnt<=tot&&now!=0){ cnt++; ff[i][j]|=1<<(now-1); // printf("ff[%lld][%lld]=%lld now=%lld\n",i,j,ff[i][j],now); now=fa[now]; } } } f[n+1][0]=1; for(ll i=n;i>=1;i--){ for(ll j=0;j<=maxn;j++){ if(!f[i+1][j]) continue ; for(ll k=1;k<=n;k++){ f[i][j^ff[i][k]]|=f[i+1][j]; // printf("f[%lld][%lld]=%lld i+1=%lld j=%lld\n",i,j^ff[i][k],f[i+1][j],i+1,j); } f[i][j]|=f[i+1][j]; // printf("f[%lld][%lld]=%lld\n",i,j,f[i][j]); // printf("mudi=%lld\n",mudi); if(f[i][mudi]){ printf("%lld\n",n-i+1); return 0; } } } }
午餐
题解
考场真是什么也没想出来
暴力都没打对,真是没救了
还好我现在稍微会了一点
有一个奇怪的子任务:不存在确定没有学会毒瘤算法的同学。
看上去这个子任务给的性质好像没什么用
我们还是可以推一推
贪心取L即可
证明感性理解一下
于是f[x]=min(f[x],L)
最短路形式,可以用最短路转移
然后将这个子任务推广
如果存在没有学会毒瘤算法的同学就是相当于给上述转移加了一个限制条件
例如
现有wwb,whs二人
已知wwb学习毒瘤算法时间在>R,那么就意味着这次吃饭时whs也不会毒瘤算法
仍然贪心考虑
whs和wwb二人吃饭于L,然后whs在L+1学会毒瘤算法,就满足限制了
于是lim[x]=max(L+1)
先把lim算出来,再转移f就可以了
代码
#include<bits/stdc++.h> using namespace std; #define ll long long #define A 1111111 ll n,m,tot; ll vis[A],mn[A],mx[A],head[A],nxt[A],ver[A],dis[A],flag[A],lst[A],lim[A]; struct node{ ll x,y,l,r; node(){} node(const ll &a,const ll &b,const ll &c,const ll &d){x=a,y=b,l=c,r=d;} }u[A]; void add(ll x,ll y,ll minn,ll maxx){ nxt[++tot]=head[x],ver[tot]=y,head[x]=tot,mn[tot]=minn,mx[tot]=maxx; } void pre_spfa(){ deque<ll> q; for(ll i=1;i<=n;i++){ scanf("%lld",&lst[i]); if(lst[i]==-1) lim[i]=1e9+7,vis[i]=1,q.push_back(i); else vis[i]=0; } while(!q.empty()){ ll x=q.front();q.pop_front(); vis[x]=0; for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i],minn=mn[i],maxx=mx[i]; if(lim[x]>maxx){ if(lim[y]<minn+1){ lim[y]=minn+1; if(!vis[y]){ vis[y]=1; q.push_back(y); } } } } } } void spfa(){ deque<ll> q; for(ll i=1;i<=n;i++) vis[i]=0,dis[i]=1e9+7; dis[1]=0;q.push_back(1); while(!q.empty()){ ll x=q.front();q.pop_front(); vis[x]=0; for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i],minn=mn[i],maxx=mx[i],g=max(max(lim[y],minn),dis[x]); // printf("y=%lld minn=%lld maxx=%lld g=%lld\n",y,minn,maxx,g); if(dis[y]>g&&g<=maxx){ dis[y]=g; // printf("dis[%lld]=%lld\n",y,dis[y]); if(!vis[y]){ vis[y]=1; q.push_back(y); } } } } } int main(){ freopen("lunch.in","r",stdin); freopen("lunch.out","w",stdout); scanf("%lld%lld",&n,&m); for(ll i=1;i<=m;i++){ ll x,y,a,b; scanf("%lld%lld%lld%lld",&x,&y,&a,&b); add(x,y,a,b); add(y,x,a,b); u[i]=node(x,y,a,b); } pre_spfa(); spfa(); for(ll i=1;i<=n;i++) if(lst[i]==1&&dis[i]>1e9){ puts("Impossible\n"); return 0; } for(ll i=1;i<=m;i++){ ll x=u[i].x,y=u[i].y; if(lst[x]==-1&&dis[y]<u[i].l){ puts("Impossible\n"); return 0; } if(lst[y]==-1&&dis[x]<u[i].l){ puts("Impossible\n"); return 0; } } // for(ll i=1;i<=n;i++) // printf("lim=%lld dis=%lld\n",lim[i],dis[i]); for(ll i=1;i<=m;i++){ ll x=u[i].x,y=u[i].y; if(lst[x]==-1||lst[y]==-1) printf("%lld\n",u[i].l); else printf("%lld\n",max(dis[x],dis[y])>u[i].r?u[i].l:max(u[i].l,max(dis[x],dis[y]))); } }
我已没有下降的余地