A.dp水题,不多讲
B.
首先我们显然贪心一下,及操作顺序按时间从小到大排序一下,那么我们直接用个priority维护一下z的最大值,因为如果时间超出了限制,那么我们一定是贪心选从前z最大的来花金币
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
int n;
struct node{
int x,y,z;
}v[MAXN];
double ans;
priority_queue<pair<int,int> >q;
bool cmp(node x,node y)
{
return x.y<y.y;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d%d%d",&v[i].z,&v[i].x,&v[i].y);
sort(v+1,v+n+1,cmp);
int time=0;
for (int i=1;i<=n;i++)
{
time+=v[i].x;
q.push(make_pair(v[i].z,v[i].x));
while (time>v[i].y)
{
pair<int,int> x=q.top(); q.pop();
if (time-x.second==v[i].y)
{
time=v[i].y; ans+=x.second*1.0/(1.0*x.first); break;
}
else if (time-x.second<v[i].y)
{
ans+=(time-v[i].y)*1.0/(1.0*x.first);
x.second-=(time-v[i].y); time=v[i].y;
q.push(x); break;
} else {
time-=x.second; ans+=x.second*1.0/(1.0*x.first);
}
}
}
printf("%.1lf\n",ans);
}
C.就是所有边权和×2减直径
D.这是神仙qy教我的,膜一发.
我们考虑一下右端以r为结尾的最大值
我们推一发式子就得到了
我们发现这就可以看成y=kx+b,此时就是求截距最大值
这就可以用斜率优化了
但是实际上这个斜率即f(r)并不是单调的,所以我们在维护下凸壳的时候并不能把队首给删掉,因为斜率的不确定性,需要二分寻找斜率(其实思考斜率优化本质显然)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=2e5+10;
struct node {
ll x,y;
}q[MAXN];
int n;
ll s[MAXN],a[MAXN],f[MAXN],sum[MAXN],ans;
int len;
bool pan1(int x,int y,ll z)
{
return (q[y].y-q[x].y)>=z*(q[y].x-q[x].x);
}
ll findans(int l,int r,ll x)
{
if (l==r) return l;
int mid=(l+r)/2;
if (pan1(mid,mid+1,x))
{
return findans(mid+1,r,x);
} else return findans(l,mid,x);
}
bool pan(int x,int y,int z)
{
return (q[x].y-q[y].y)*(q[y].x-q[z].x)>=(q[y].y-q[z].y)*(q[x].x-q[y].x);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
f[i]=(f[i-1]+a[i]);
s[i]=(s[i-1]+(ll)i*a[i]);
sum[i]=((ll)i*f[i]-s[i]);
}
len=1;
q[len].x=0;
q[len].y=0;
ans=-100000000000000000;
for (int i=1;i<=n;i++)
{
int t=findans(1,len,f[i]);
ans=max(ans,q[t].y-q[t].x*f[i]+s[i]);
q[++len].x=i; q[len].y=sum[i];
if (len>=3)
while (pan(len,len-1,len-2))
{
len--; q[len].x=q[len+1].x; q[len].y=q[len+1].y;
if (len<3) break;
}
}
printf("%lld\n",ans);
}
E.
又是一道莫比乌斯反演题..
让你求:
其中g函数的定义如下:
x可以被分解成若干质数的乘积
那么
我们冷静分析一下,因为他所要求的是乘积,那么我们就应该知道利用连续一段的gcd为x的出现个数是相同的,这样有根号段
所以我们首先可以预处理出g函数这个东西直接欧筛就行了
然后我们思考一下反演
设
则上式为
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7;
const int N=250000;
ll sum[N+10],mu[N+10],ans[N+10],inv[N+10];
int len;
bool p[N+10];
int prime[N+10];
int T;
ll n,m;
ll ksm(ll x,ll y)
{
ll ans=1;
for (;y;y>>=1,x=(x*x)%mod) if (y&1) ans=(ans*x)%mod;
return ans;
}
ll pan(ll x,ll y)
{
if (y==1) return x;
else if (y==-1) return ksm(x,mod-2); else return 1;
}
void init()
{
sum[1]=1; mu[1]=1;
for (int i=2;i<=N;i++)
{
if (!p[i])
{
sum[i]=1; prime[++len]=i; mu[i]=-1;
}
for (int j=1;prime[j]*i<=N;j++)
{
p[prime[j]*i]=1;
sum[prime[j]*i]=sum[i]+1;
if (i%prime[j]==0) { mu[i*prime[j]]=0; break;}
else mu[i*prime[j]]=-mu[i];
}
}
for (int i=1;i<=N;i++) ans[i]=1;
for (int i=1;i<=N;i++)
{
for (int j=1;j*i<=N;j++)
ans[i*j]=(ans[i*j]*pan(sum[i],mu[j]))%mod;
}
inv[0]=1;
for (int i=1;i<=N;i++) inv[i]=ksm(ans[i],mod-2);
for (int i=2;i<=N;i++) ans[i]=(ans[i-1]*ans[i])%mod;
for (int i=2;i<=N;i++) inv[i]=(inv[i]*inv[i-1])%mod;
}
int main()
{
scanf("%d",&T);
init();
while (T--)
{
scanf("%lld%lld",&n,&m);
ll k=0,s=1;
for (ll i=1;i<=n&&i<=m;i=k+1)
{
k=min(n/(n/i),m/(m/i));
s=(s*ksm((ans[k]*inv[i-1]%mod)%mod,(n/i)*(m/i)))%mod;
}
printf("%lld\n",s);
}
}
F.
我们考虑一下这一定是网络流
所以我们简化一下模型即是一对点的关系边
再加上我们分类讨论一下最小割的情况,最后人工手动平衡点权即可,就可以得到答案
具体细节不讲了
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
const int MAXN=1e3+10;
struct node{
int u,to,w;
}edge[MAX];
int head[MAXN],arrange[MAXN],w[MAXN],cur[MAXN],l[MAXN];
int x,y,n,v0,v1,v2,ans,s,t,q,k;
void add(int x,int y,int z)
{
edge[k].u=y;
edge[k].to=head[x];
edge[k].w=z;
head[x]=k++;
}
bool bfs(){
memset(arrange,0,sizeof(arrange));
arrange[s]=1;
queue<int>q;
q.push(s);
while (!q.empty())
{
int p=q.front(); q.pop();
if (t==p) return 1;
for (int i=head[p];i!=-1;i=edge[i].to)
{
int u=edge[i].u;
if (!arrange[u]&&edge[i].w)
{
arrange[u]=arrange[p]+1;
q.push(u);
}
}
}
return 0;
}
int dfs(int now,int maxlow)
{
if (now==t) return maxlow;
int ret=0;
for (int &i=cur[now];i!=-1;i=edge[i].to)
{
int u=edge[i].u;
if (edge[i].w&&arrange[u]==arrange[now]+1)
{
int f=dfs(u,min(maxlow-ret,edge[i].w));
edge[i].w-=f; edge[i^1].w+=f;
ret+=f;
if (maxlow==ret) return ret;
}
}
return ret;
}
int dinic()
{
int ans=0;
while (bfs())
{
memcpy(cur,head,sizeof(head));
ans+=dfs(s,0x3f3f3f3f);
}
return ans;
}
int main()
{
scanf("%d%d",&n,&q);
memset(head,-1,sizeof(head));
for (int i=1;i<=n;i++) scanf("%d",&w[i]);
for (int i=1;i<=n;i++) ans+=w[i];
s=n+1,t=n+2;
for (int i=1;i<=q;i++)
{
scanf("%d%d%d%d%d",&x,&y,&v0,&v1,&v2);
ans+=v0+v1;
add(x,y,(v0+v1)/2+v2); add(y,x,0);
add(y,x,(v0+v1)/2+v2); add(x,y,0);
w[x]+=v0/2; w[y]+=v0/2;
l[x]+=v1/2; l[y]+=v1/2;
}
for (int i=1;i<=n;i++)
{
add(s,i,w[i]); add(i,s,0);
add(i,t,l[i]); add(t,i,0);
}
printf("%d\n",ans-dinic());
}