福建集训day 1题解

来源:互联网 发布:tensorflow seq2seq 编辑:程序博客网 时间:2024/04/23 15:16

浪了一个月总算有东西写了

还有9天的题解没写……这一天的也不太能算是改完了

T1:

一个DAG,可以删边,边有依赖性,删x必须删y,求从点1开始走的步数的期望的最大值

对于一个点,答案显然为f[i]=sigma(f[j]*a[j])/sigma(a[j])

若选i->j这条边,a[j]为1,否则a[j]为0

既然a[j]只能为1或0,而且在满足条件的情况下a[j]可以随便设,那么这显然是一个01分数规划的模型

二分答案,那么转换为这样一个问题

有一些边,每条边有一个权值,问在满足条件的情况下能不能选一些边使得他们的平均数大于一个数

我们把“边”当成点,依赖关系进行连边,例如选x必须选y连一条边x->y,把点权改成这条边的权值减去当前二分的这个答案

那么我们就要选一些点使得点权和大于0

给定一些点,规定选x必须选x的后继节点,求点权和的最大值

显然是一个最大权闭合子图模型

所以直接上模型求出点权和的最大值,再判断这个最大值能不能大于0就可以啦

AC code:

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
#define eps 0.0001 
#define mid ((l+r)/2)
struct lwn{
int u,v;
double flow,cap;
} a[5050];
vector<int> g[550]; 
int cur[550];
int num[1050];
int p[550];
int d[550];
int from[550];
int to[550];
vector<int> gg[100];
int in[100];
int tot,m,i,n,k;
int xx[2050];
int yy[2050];
int tp[100];
double f[100];
void link(int x,int y,double z)
{
g[x].push_back(++tot);
a[tot].u=x;a[tot].v=y;
a[tot].flow=0;a[tot].cap=z;
}
double maxflow(int s,int t)
{
memset(cur,0,sizeof(cur));
memset(num,0,sizeof(num));
memset(d,0,sizeof(d));
int x=s;double ans=0;num[0]=m+2;
while (d[s]<m+2){
if (x==t){
double jb=2147483647;
while (x!=s){
jb=min(jb,a[p[x]].cap-a[p[x]].flow);
x=a[p[x]].u;
}
x=t;ans+=jb;
while (x!=s){
a[p[x]].flow+=jb;
a[(p[x]+tot) % (tot << 1)].flow-=jb;
x=a[p[x]].u;
}
}
bool zw=true;
for (i=cur[x];i<g[x].size();i++) if (a[g[x][i]].cap>a[g[x][i]].flow && d[x]==d[a[g[x][i]].v]+1){
p[a[g[x][i]].v]=g[x][i];cur[x]=i;x=a[g[x][i]].v;
zw=false;break;
}
if (zw){
cur[x]=0;if (--num[d[x]]==0) return ans;
d[x]=m+2;
for (i=cur[x];i<g[x].size();i++) if (a[g[x][i]].cap>a[g[x][i]].flow) d[x]=min(d[x],d[a[g[x][i]].v]+1);
if (x!=s) x=a[p[x]].u;
}
}
return ans;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (i=1;i<=m;i++){
scanf("%d%d",&from[i],&to[i]);
gg[from[i]].push_back(to[i]);
in[to[i]]++;
}
for (i=1;i<=k;i++) scanf("%d%d",&xx[i],&yy[i]);
queue<int> q;int tott=0;
for (i=1;i<=n;i++) if (!in[i]) q.push(i);
while (!q.empty()){
int wtf=q.front();q.pop();tp[++tott]=wtf;
for (i=0;i<gg[wtf].size();i++) if (--in[gg[wtf][i]]==0) q.push(gg[wtf][i]);
}
do{
bool zw=true;
for (i=1;i<=m;i++) if (from[i]==tp[tott]) zw=false;
if (zw){
f[tp[tott]]=0;
continue;
}
double l=0,r=n-1;
while (r-l>eps){
tot=0;double wtf=0;
for (i=1;i<=m+2;i++) g[i].clear();
for (i=1;i<=m;i++) if (from[i]==tp[tott] && f[to[i]]>mid){
link(m+1,i,f[to[i]]-mid);
wtf+=f[to[i]]-mid;
}
else if (from[i]==tp[tott]) link(i,m+2,mid-f[to[i]]);
for (i=1;i<=k;i++) if (from[xx[i]]==tp[tott]) link(xx[i],yy[i],2147483647);
for (i=1;i<=tot;i++){
g[a[i].v].push_back(i+tot);
a[i+tot].u=a[i].v;
a[i+tot].v=a[i].u;
a[i+tot].cap=a[i+tot].flow=0;
}
if (wtf==maxflow(m+1,m+2)) r=mid;
else l=mid;
}
f[tp[tott]]=l+1;
}while (--tott);
printf("%.6lf\n",f[1]);
return 0;
 } 

T2:一堆一次函数,多个询问,每个询问给出l,r,x求fr(fr-1(……fl(x))),要求支持修改

显然两个区间的答案可以合并

所以直接裸上线段树,我写的zkw

AC code:

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define Mod 1000000007
pair<int,int> a[800050];
int n,m,i;
int main()
{
freopen("func.in","r",stdin);
freopen("func.out","w",stdout);
scanf("%d%d",&n,&m);
int p=ceil(log2(n+1));p=1 << p;
for (i=1;i<=n;i++) scanf("%d%d",&a[i+p].first,&a[i+p].second);
for (i=p-1;i>=1;i--){
a[i].first=(1LL*a[i << 1].first*a[i << 1|1].first) % Mod;
a[i].second=(0LL+a[i << 1|1].second+1LL*a[i << 1|1].first*a[i << 1].second) % Mod;
}
while (m--){
char ch=getchar();
while (ch!='Q' && ch!='M') ch=getchar();
if (ch=='M'){
int x;pair<int,int> psz;
scanf("%d%d%d",&x,&psz.first,&psz.second);
int jb=x+p;a[jb]=psz;jb>>=1;
while (jb){
a[jb].first=(1LL*a[jb << 1].first*a[jb << 1|1].first) % Mod;
a[jb].second=(0LL+a[jb << 1|1].second+1LL*a[jb << 1|1].first*a[jb << 1].second) % Mod;
jb>>=1;
}
}
else{
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
l=l+p-1;r=r+p+1;
pair<int,int> lpsz=make_pair(1,0);pair<int,int> rpsz=make_pair(1,0);
while (r-l>1){
if (!(l & 1)){
lpsz.first=(1LL*a[l^1].first*lpsz.first) % Mod;
lpsz.second=(0LL+a[l^1].second+1LL*lpsz.second*a[l^1].first) % Mod;
}
if (r & 1){
rpsz.second=(0LL+rpsz.second+1LL*a[r^1].second*rpsz.first) % Mod;
rpsz.first=(1LL*rpsz.first*a[r^1].first) % Mod;
}
l>>=1;r>>=1;
}
lpsz.first=(1LL*rpsz.first*lpsz.first) % Mod;
lpsz.second=(0LL+rpsz.second+1LL*lpsz.second*rpsz.first) % Mod;
printf("%d\n",(0LL+1LL*lpsz.first*x+lpsz.second) % Mod);
}
}
fclose(stdin);fclose(stdout);
return 0;
}

T3:五维偏序,有一堆五维空间上的点,每个询问给出一个点,求有多少个点满足每一维都比所给的点小,强制在线

这题我写的挫跑了7s+,所以并不能算AC,然而答案是对的(std也跑了7s+是什么鬼啊)

五维偏序?树套树套树套树?显然不是

我们对于每一维按坐标排序,预处理f[i][j],表示第i维,这一维坐标前j*sqrt(n)小的点集

然后对于每一个询问,我们把每一维放在坐标里lower_bound一下,然后可以O(sqrt(n))求出满足这一维比所给的点小的点集

然后我们把每一维的点集and起来就可以得到答案了

用什么维护点集?显然我们要维护数据结构支持插入一个点和与另一个点集取与操作

显然bitset可以办到

时间复杂度为3*5*nq/32,十分玄学

嗯这是一道很好的卡常题

跑了7s+的code:

#include <cstdio>
#include <bitset>
#include <algorithm>
#include <cmath>
using namespace std;
bitset<50050> ans[6][300];
int n,m,i,lstans;
pair<int,int> a[50050],b[50050],c[50050],d[50050],e[50050];
int main()
{
freopen("Score.in","r",stdin);
freopen("Score.out","w",stdout);
int t;scanf("%d",&t);
while (t--){
scanf("%d%d",&n,&m);int p=trunc(sqrt(n));
for (i=1;i<=n;i++) scanf("%d%d%d%d%d",&a[i].first,&b[i].first,&c[i].first,&d[i].first,&e[i].first);
for (i=1;i<=n;i++) a[i].second=b[i].second=c[i].second=d[i].second=e[i].second=i;
sort(a+1,a+n+1);sort(b+1,b+n+1);sort(c+1,c+n+1);sort(d+1,d+n+1);sort(e+1,e+n+1);
bitset<50050> psz;ans[1][0]=psz;
for (i=1;i<=n;i++){
psz.set(a[i].second);
if (!(i % p)) ans[1][i/p]=psz;
}
psz.reset();
ans[2][0]=psz;
for (i=1;i<=n;i++){
psz.set(b[i].second);
if (!(i % p)) ans[2][i/p]=psz;
}
psz.reset();
ans[3][0]=psz;
for (i=1;i<=n;i++){
psz.set(c[i].second);
if (!(i % p)) ans[3][i/p]=psz;
}
psz.reset();
ans[4][0]=psz;
for (i=1;i<=n;i++){
psz.set(d[i].second);
if (!(i % p)) ans[4][i/p]=psz;
}
psz.reset();
ans[5][0]=psz;
for (i=1;i<=n;i++){
psz.set(e[i].second);
if (!(i % p)) ans[5][i/p]=psz;
}
scanf("%d",&m);lstans=0;
while (m--){
pair<int,int> gh1,gh2,gh3,gh4,gh5;gh1.second=gh2.second=gh3.second=gh4.second=gh5.second=2147483647;
scanf("%d%d%d%d%d",&gh1.first,&gh2.first,&gh3.first,&gh4.first,&gh5.first);
gh1.first^=lstans;gh2.first^=lstans;gh3.first^=lstans;gh4.first^=lstans;gh5.first^=lstans;
psz.set();bitset<50050> fdc;
int wtf=lower_bound(a+1,a+n+1,gh1)-a-1,zz=(wtf/p)*p+1;
fdc=ans[1][wtf/p];
for (;zz<=wtf;zz++) fdc.set(a[zz].second);psz&=fdc;
wtf=lower_bound(b+1,b+n+1,gh2)-b-1,zz=(wtf/p)*p+1;
fdc=ans[2][wtf/p];
for (;zz<=wtf;zz++) fdc.set(b[zz].second);psz&=fdc;
wtf=lower_bound(c+1,c+n+1,gh3)-c-1,zz=(wtf/p)*p+1;
fdc=ans[3][wtf/p];
for (;zz<=wtf;zz++) fdc.set(c[zz].second);psz&=fdc;
wtf=lower_bound(d+1,d+n+1,gh4)-d-1,zz=(wtf/p)*p+1;
fdc=ans[4][wtf/p];
for (;zz<=wtf;zz++) fdc.set(d[zz].second);psz&=fdc;
wtf=lower_bound(e+1,e+n+1,gh5)-e-1,zz=(wtf/p)*p+1;
fdc=ans[5][wtf/p];
for (;zz<=wtf;zz++) fdc.set(e[zz].second);psz&=fdc;
printf("%d\n",lstans=psz.count());
}
}
fclose(stdin);fclose(stdout);
return 0;
}

0 0
原创粉丝点击