前言:我从未见过如此凶残的猪。。。会修路,会撒猪粮,会高科技,会有闲情逸致玩数学,还会吃猪???看来我还是Naive
----------------------------------------------------------------------------------分割线-------------------------------------------------------------------------------------------------
猪猪划船(boat)
【题目描述】
6只可爱的猪猪们一起旅游,其中有3只大猪A,B,C,他们的孩子为3只小猪a,b,c。由于猪猪们十分凶残,如果小猪在没有父母监护的情况下,和其他的大猪待在一起,就会被吃掉。
拦在他们面前的是一条大河,河上有一只只有1个船桨且限载2只猪的小船,只有A,B,C,a会划船。他们独自划船单程需要的时间为tA,tB,tC,ta,如果搭载另一只猪时间翻倍。你需要求出所有小猪过河的最短时间。
【输入数据】
一行,4个整数,tA,tB,tC,ta。
【输出数据】
一行,一个整数,表示最短时间。
【样例输入】
10 10 10 10
【样例输出】
220
【数据范围】
对于20%的数据:tA=tB=tC=ta
对于60%的数据:ta<=tA<=tB<=tC
对于100%的数据:tA,tB,tC,ta<=100
这是一道结论题,我们可以先手动尝试一下,发现合法的情况总数并不多(虽然我说的很轻松但是当时并没有尝试出全部的)
我们就根据分类和不分类分成3个阶段取min就好啦

#include<iostream> #include<cstdlib> #include<cstdio> #include<algorithm> using namespace std; int A,B,C,a,ans; inline void Jimmy(){ scanf("%d%d%d%d",&A,&B,&C,&a); ans+=min(a*6,min((a+B)*3,(a+C)*3)); //阶段一 ans+=(B+C)*2+min(A,a)*2+min(B,C)*4+a; //阶段二 ans+=min(a*5,min(a*2+C*3,a*2+B*3)); //阶段三 printf("%d",ans); } int main(){ freopen("boat.in","r",stdin); freopen("boat.out","w",stdout); Jimmy(); return 0; }
小猪星球(planet)
【题目描述】
小猪所在的星系有n个星球,用1~n标号,其中有一些星球之间有单向的隧道相连。由于超时空隧道的存在,通过一个隧道的时间可能为0或负数。现在小猪们决定从1号星球出发,沿着最短路径到达n号星球。
科学家猪小聪发明了一种神奇的装置,使得飞船在每个隧道中运行的时间都增加一个相同的常数(可以为0或负数),你需要确定这个常数使得旅途的总时间非负且最小。
【输入数据】
输入文件包含多组数据,第一行为数据组数T。
对于每一组数据,第一行两个整数V,E,表示星球的个数和隧道的个数。接下来E行,每行3个整数i,j,t,表示从i号星球到j号星球有一条耗时为t的单向隧道。
【输出数据】
共T行,每行一个整数,表示从1号星球到n号星球最短的时间。如果不能从1号星球到达n号星球,输出-1。
【样例输入】
1
4 5
1 2 1
1 3 1
2 3 -3
3 1 1
3 4 1
【样例输出】
2
【样例解释】
如果不使用科技(也可以理解成是使用科技,但确定常数为0,所有的隧道时间不变),则1->2->3->1->2->3……->4的时间为负无穷,不符合要求。若使用科技,确定常数为1,则1->2->3->4的最短时间为2。
【数据范围】
对于100%的数据,N<=100,E<=N(N+1)/2,|t|<=10^5,i,j<=N
友情提示:可能有重边和自环
用floyd判自环,二分题目中的常数c,注意判负环

#include<iostream> #include<cstdlib> #include<cstdio> #include<algorithm> #define N 110 #define M 5050 #define inf 100000010 using namespace std; int T,n,m,cnt,g[N],q[N*M],a[N][N],deg[N],dis[N],h,t,inq[N]; struct Nee{ int nxt,to,w; }e[M]; inline int check2(int x){ //二分常数c for(int i=1;i<=n;i++) deg[i]=0,dis[i]=inf,inq[i]=0; int u=1,h=1,t=0; q[++t]=u;inq[u]=1;deg[u]++;dis[u]=0; while(h<=t){ u=q[h++];inq[u]=0; for(int i=g[u];i;i=e[i].nxt){ if(a[e[i].to][n]&&dis[u]+e[i].w+x<dis[e[i].to]){ dis[e[i].to]=dis[u]+e[i].w+x; if(!inq[e[i].to]){ if(++deg[e[i].to]>m) return -1; q[++t]=e[i].to; inq[e[i].to]=1; } } } } return dis[n]; } inline int check1(){ //检验是否能到达n for(int i=1;i<=n;i++) inq[i]=0; int u=1,h=1,t=0;q[++t]=u;inq[u]=1; while(h<=t){ u=q[h++]; for(int i=g[u];i;i=e[i].nxt){ if(!inq[e[i].to]){ inq[e[i].to]=1; q[++t]=e[i].to; } } } return inq[n]; } inline void addedge(int x,int y,int z){ e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].w=z; } inline void Jimmy(){ scanf("%d%d",&n,&m); cnt=0; for(int i=1;i<=n;i++) g[i]=0; for(int i=1,j,k,w;i<=m;i++){ scanf("%d%d%d",&j,&k,&w); addedge(j,k,w); } if(!check1()){ printf("-1 "); return; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=0; for(int i=1;i<=n;i++) for(int j=g[i];j;j=e[j].nxt) a[i][e[j].to]=1; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]|=a[i][k]&a[k][j]; a[n][n]=1;int l=-100001,r=100001; while(l<r){ int mid=(l+r)>>1; if(check2(mid)>=0) r=mid; else l=mid+1; } printf("%d ",check2(l)); } int main(){ freopen("planet.in","r",stdin); freopen("planet.out","w",stdout); scanf("%d",&T); while(T--) Jimmy(); return 0; }
小猪送货(deliver)
【题目描述】
小猪所在的星系有n个星球从左到右排成一排,用1~n标号。每个星球有建设有一个工厂,住着若干居民。猪粮是猪猪星系的重要的物资,第i个城市的工厂能够生产pi个单位的猪粮,第i个城市最多可以卖出si个单位猪粮。对于任意1<=i<j<=n,存在着一条从i到j的单向道路,最多可以通过这条道路运输c个单位的猪粮,你需要计算最多能够卖出多少猪粮。
【输入数据】
第一行两个整数n,c
第二行n个整数,第i个整数表示pi
第三行n个整数,第i个整数表示si
【输出数据】
一行,一个整数,表示最多可以卖出的猪粮的单位数
【样例输入1】
5 1
7 4 2 1 0
1 2 3 4 5
【样例输出1】
12
【样例输入2】
4 3
13 10 7 4
4 7 10 13
【样例输出2】
34
【数据范围】
对于20%的数据:c=0
对于60%的数据:n<=100
对于100%的数据:n<=10000,0<=c,pi,si<=10^9
P.S.:差评!单身狗拒绝猪粮狗粮一切粮 QAQ !!!
对于20分的数据我们在p和s里取个min求和就好啦
对于60分的数据,考虑网络流,(P.S.艾特当时说我觉得这道题像网络流的老何)
源点s向i建边,每个点向汇点t连边,两点之间从小到大ij也建边
即(s,i)=pi,(i,j)=c,(i,t)=si
但是这样子边太多了不够优秀啊,怎么办呢?观察到这题的水流限度很特殊,只有pi,si和c,而且c的连边在数列上是有规律的,都为c的水流限度又可以看做和边的先后没有关系,那就是满足无后向性,我们考虑dp
f[i]][j]表示以前i个点,有j个和t连边的最小割,那么就有f[i][j]=min{f[i-1][j]+j*c+p[i],f[i-1][j-1]+s[i]},对于源点出来的边对j没有影响,但是割掉之后因为是最小割(最小割即为最大流),那么割掉s的割边,由于还和t相连,所以j条与t相连的边可以流向它
本题滋磁dp是由于水流限度的特殊性(均为s)以及1-n和建边i,j的从小到大保证了无后效性

#include<iostream> #include<cstdlib> #include<cstdio> #include<algorithm> #define N 10010 #define min(a,b) (a<b?a:b) #define inf 10000000000010LL using namespace std; long long c,p[N],s[N],f[2][N],ans=inf; int n; inline void Jimmy(){ scanf("%d%lld",&n,&c); for(int i=1;i<=n;i++) scanf("%lld",&p[i]); for(int i=1;i<=n;i++) scanf("%lld",&s[i]); for(int i=1;i<=n;i++) f[0][i]=f[1][i]=inf; f[1][0]=p[1];f[1][1]=s[1]; for(int i=2;i<=n;i++){ f[i&1][0]=f[i&1^1][0]+p[i]; for(int j=1;j<=n;j++) f[i&1][j]=min(f[i&1^1][j]+1LL*j*c+p[i],f[i&1^1][j-1]+s[i]); } for(int i=0;i<=n;i++) ans=min(ans,f[n&1][i]); printf("%lld",ans); } int main(){ freopen("deliver.in","r",stdin); freopen("deliver.out","w",stdout); Jimmy(); return 0; }
小猪数数(math)
【题目描述】
猪小聪和猪小明在一个小时的时间里,A完了前三题,他们无聊地说:“咱们来玩个游戏消磨时间吧……”
在这个游戏中,猪小聪和猪小明每个人手上有一台电脑,一开始双方的电脑上的数字都是1。现在猪小聪和猪小明按照任意的顺序执行操作a=a+b(其中a为自己电脑上的数字,b为对方电脑上的数字),例如按照小聪-小明-小明执行后双方的数字为2 5。
现在在他们玩了若干轮之后,双方电脑上的数字为N M,可惜的是他们忘记了他们到底玩了多少轮,你需要求出他们至少玩了多少轮。
【输入数据】
2个整数,表示N,M。
【输出数据】
1个整数,表示最少玩过的轮数。如果根本不可能出现符合要求的结果,输出-1。
【样例输入1】
2 5
【样例输出1】
3
【样例输入2】
2 2
【样例输出2】
-1
【数据范围】
对于30%的数据,1<=N,M<=10
对于60%的数据,1<=N,M<=1000
对于100%的数据:N,M和ans均不会爆long long (ans表示输出的答案)
本套题的水题呀,YY一下过程很容易发现这就是更相减损的过程,我们用%来代替就好了,也就是求gcd的过程中累计答案
当然对于gcd(n,m)不为1的输出-1就好了

#include<iostream> #include<cstdlib> #include<cstdio> #include<algorithm> using namespace std; long long n,m,ans; inline long long gcd_(long long x,long long y){ return y==0?x:gcd_(y,x%y); } inline void gcd(long long x,long long y){ if(y==0) return; ans+=x/y; gcd(y,x%y); } inline void Jimmy(){ scanf("%lld%lld",&n,&m); if(gcd_(n,m)!=1){ printf("-1"); return; } gcd(n,m); printf("%d",ans-1); } int main(){ freopen("math.in","r",stdin); freopen("math.out","w",stdout); Jimmy(); return 0; }