版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugar_free_mint/article/details/86692272
今天你AK了吗
JZOJ 4244 yi
分析
真是一道大水难题,主要是往返这两个字比较坑,剩下的贪心搞定,题目过水,就不贴代码了
JZOJ 4245 er
题目
给你
个数,然后让你经过
次修改后使它(们)乘积最大,输出自然对数
修改如下:
- ,使某个数变为 (最多只有一次)
- ,使某个数增加
- ,使某个数乘
分析
首先,修改的次序肯定是先赋值,再增加,最后乘,从大到小排序
,首先
的时候很好处理,我就不解释了,问题是
怎么处理,那首先乘在一起是不受影响的,那么关键是处理加,那深搜应该是会爆炸的,只想到了动态规划
设
表示选完前
个(已排序),第一个装备威力为
,两个装备威力的最大乘积,那么
然后由于会赋值,所以要跑3次
代码
#include <bits/stdc++.h>
#define rr register
using namespace std;
int n,m,k,a0,a1,aux,n1,n2,sum1[101],add[101];
double sum2[101],ans;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void answ(int a0,int a1){
rr int f[2][200001],res[101]; memset(f[0],0xcf,sizeof(f[0]));
sum1[0]=a0+a1; memset(res,0,sizeof(res)); res[0]=f[0][a0]=a0*a1;
for (rr int i=1;i<=n1;++i) sum1[i]=sum1[i-1]+add[i];
for (rr int i=1;i<=k;++i){
memset(f[i&1],0xcf,sizeof(f[i&1]));
for (rr int j=a0;j<=sum1[i];++j){
f[i&1][j]=max(f[i&1][j],f[1-(i&1)][j]+add[i]*j);
if (j+add[i]<=sum1[i])
f[i&1][j+add[i]]=max(f[i&1][j+add[i]],f[1-(i&1)][j]+add[i]*(sum1[i-1]-j));
res[i]=max(res[i],f[i&1][j]);
}
}
for (rr int i=0;i<=k;++i)
ans=max(ans,log(res[min(i,n1)])+sum2[min(k-i,n2)]);
}
inline void func(){
answ(a0,a1);
if (aux) --k,answ(aux,a1),answ(a0,aux);
}
signed main(){
n=iut(); m=iut(); k=iut();
a0=iut(); if (n>1) a1=iut(); sum1[0]=a0+a1;
for (rr int i=1;i<=m;++i){
rr int x=iut(),y=iut();
if (x==3&&y==1) --i,--m;
else{
if (x==1) aux=y;
else if (x==2) add[++n1]=y;
else sum2[++n2]=log(y);
}
}
sort(add+1,add+1+n1); reverse(add+1,add+1+n1);
sort(sum2+1,sum2+1+n2); reverse(sum2+1,sum2+1+n2);
for (rr int i=1;i<=n1;++i) sum1[i]=sum1[i-1]+add[i];
for (rr int i=1;i<=n2;++i) sum2[i]+=sum2[i-1];
if (n==1){
for (rr int i=0;i<=k;++i){
ans=max(ans,log(sum1[min(i,n1)])+sum2[min(k-i,n2)]);
if (i<k&&aux) ans=max(ans,log(sum1[min(i,n1)]+aux-a0)+sum2[min(k-i-1,n2)]);
}
}
else func();
return !printf("%.3lf",ans);
}
JZOJ 4246 san
题目
问每个点经过多少个无序点对 的最短路且其长度为奇数
分析
那么这道题首先知道 是过不了的,所以要另辟蹊(xī)径,朴素的算法计算冗余的地方就是每条路径都得算一次,这就导致了时间巨大,那该怎么办呢,首先对于每个点先求一次单源最短路径,然后其实这个图已经变成了有向无环图,那么对于每个点统计子节点的方案和,然后再相加即可
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#include <deque>
#define rr register
using namespace std;
struct node{int y,w,next;}e[6011]; bool v[1001];
int n,m,k=1,ls[1001],ans[1001],dis[1001],t[1001];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void add(int x,int y,int w){
e[++k]=(node){y,w,ls[x]}; ls[x]=k;
}
inline void dfs(int x,int fa){
if (dis[x]&1) t[x]=1; else t[x]=0;
for (rr int i=ls[x];i;i=e[i].next)
if (e[i].y!=fa&&dis[e[i].y]==dis[x]+e[i].w){
dfs(e[i].y,x);
t[x]+=t[e[i].y];
}
ans[x]+=t[x];
}
inline void spfa(int s){
memset(dis,127/3,sizeof(dis)); dis[s]=0;
memset(v,0,sizeof(v)); v[s]=1;
rr deque<int>q; q.push_back(s);
while (q.size()){
rr int x=q.front(); q.pop_front();
for (rr int i=ls[x];i;i=e[i].next)
if (dis[e[i].y]>dis[x]+e[i].w){
dis[e[i].y]=dis[x]+e[i].w;
if (!v[e[i].y]){
v[e[i].y]=1;
if (q.size()&&dis[e[i].y]<dis[q.front()]) q.push_front(e[i].y);
else q.push_back(e[i].y);
}
}
v[x]=0;
}
dfs(s,0);
}
signed main(){
n=iut();
for (rr int m=iut();m;--m){
rr int x=iut(),y=iut(),w=iut();
add(x,y,w); add(y,x,w);
}
for (rr int i=1;i<=n;++i) spfa(i);
for (rr int i=1;i<=n;++i) print(ans[i]),putchar(10);
return 0;
}