3/5福建四校联考

1.有3只小猪,三只大猪。大猪和其中一只小猪会划船。船最多可以坐两个人,四只小猪划船的时间是tA,tB,tC,ta,如果载人的话时间翻倍,求最小时间。

题解:暴力搜索。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define INF 2000000000
#define a A+3
#define b B+3
#define c C+3
#define to 127
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 

int t[10],ans=INF;
int s[10];
int has[10];
int d[127];

bool check()
{
    for(int i=4;i<=6;i++)
       if(has[i]!=has[i-3])
           for(int j=1;j<=3;j++)
              if(j!=i-3&&has[j]==has[i])
                      return true;
    return false;
}

bool check(int x,int y,int k)
{
    if(has[x]==k||has[y]==k)return false;
    if(x==y)return false;
    if(!(x>=4)^(y>=4))return true;
    if(x!=y-3&&y!=x-3)return false;
    return true;
}

void dfs(int k,int T,int x)
{
    if(check())return;
    if(T>=d[x^((k==0)?64:0)])return;else d[x^((k==0)?64:0)]=T;
    if((x^((k==0)?64:0))==to){ans=min(ans,T);}
    for(int i=1;i<=4;i++)if(has[i]!=k)
    {has[i]^=1;dfs(!k,T+t[i],x^s[i]);has[i]^=1;}
    for(int i=1;i<=4;i++)
        for(int j=1;j<=6;j++)
            if(check(i,j,k)) {has[i]^=1;has[j]^=1;dfs(!k,T+2*t[i],x^s[i]^s[j]);has[i]^=1;has[j]^=1;}
}

int main()
{
    freopen("boat.in","r",stdin);
    freopen("boat.out","w",stdout);
    for(int i=0;i<128;i++)d[i]=INF;
    for(int i=1;i<=4;i++)t[i]=read();s[1]=1;
    for(int i=2;i<=7;i++)s[i]=s[i-1]<<1;
    dfs(1,0,0);
    cout<<ans;
    return 0;
}

2.有一个n(n<=100)个点m条边的图,可能有负权边,你可以把所有边都加上或减去一个值,求第1个点到第n个点的距离非负的最小值。

题解:不考虑那些到不了n点的点(可以用floyd判一下),然后二分一个答案,判断有没有负环就可以了。复杂度o(能过)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
#define MAXN 100000
#define MAXL 100
#define INF 1000000000
#define inf 2000000000000LL
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
queue<int> q;
int n,m,cnt=0;
struct edge{
    int to,next;
    ll w;
}e[MAXN+5];
bool inq[MAXL+5];
ll mp[MAXL+5][MAXL+5];
ll d[MAXL+5];
int head[MAXL+5];
ll ans=INF;
bool yes;

inline void ins(int f,int t,int w)
{
    e[++cnt].next=head[f];head[f]=cnt;
    e[cnt].to=t;e[cnt].w=w;
}

void dfs(int x,int ad)
{
    if(!yes)return;inq[x]=1;
    for(int i=head[x];i;i=e[i].next)
        if(mp[e[i].to][n]<INF&&d[x]+ad+e[i].w<d[e[i].to])
        {
            d[e[i].to]=d[x]+ad+e[i].w;if(inq[e[i].to]){yes=false;return;}
            dfs(e[i].to,ad);
        }
    inq[x]=0;
}

int main()
{
    freopen("planet.in","r",stdin);
    freopen("planet.out","w",stdout);
    int T=read();
    while(T--)
    {
        n=read();m=read();cnt=0;ans=inf;memset(head,0,sizeof(head));
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)mp[i][j]=INF;
        for(int i=1;i<=n;i++)mp[i][i]=0;
        for(int i=1;i<=m;i++)
        {int u=read(),v=read(),w=read();ins(u,v,w);mp[u][v]=min(mp[u][v],(ll)w);}
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(mp[i][k]<INF&&mp[k][j]<INF&&mp[i][k]+mp[k][j]<mp[i][j]) mp[i][j]=mp[i][k]+mp[k][j];
        int l=-INF,r=INF,mid;
        while(l<=r)
        {
            mid=(l+r)>>1;yes=true;memset(inq,0,sizeof(inq));
            for(int i=1;i<=n;i++)d[i]=inf;d[1]=0;dfs(1,mid);
            if(yes&&d[n]>=0&&d[n]!=inf)r=mid-1,ans=d[n];
            else l=mid+1;
        }
        if(ans==inf)puts("-1");
        else printf("%lld\n",ans);
    }
    return 0;
}

3.有n个点,每个点有pi堆东西,最多卖掉si堆东西。对于每队1<=i<j<=n,i可以向j运送最多c堆东西,求最多能销售多少堆东西。n<=10000

题解:对于60%,n<=100,就成为了一个裸的网络流模型。每个点向S连pi,向t连si,然后每队点连c的边就可以了。

对于100%,我们发现我们每次做的事情就是求最小割,而这个图的中间的边都是c的,所以我们可以直接考虑每个点割到S还是到T

用f[i][j]表示前i个点,有j个点割到S的最小割。f[i][j]=min(f[i-1][j-1]+p[i]+(i-j)*c,f[i-1][j]+s[i])  复杂度n^2

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
#define INF 2000000000000000LL
using namespace std;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

ll f[2][10005];
ll s[10005];
ll p[10005];
int n;ll c;

int main()
{
    freopen("deliver.in","r",stdin);
    freopen("deliver.out","w",stdout);
    n=read();c=read();
    for(int i=1;i<=n;i++)p[i]=read();
    for(int i=1;i<=n;i++)s[i]=read();
    int nown=1,pre=0;
    for(int j=1;j<=n;j++)f[0][j]=f[1][j]=INF;    
    for(int i=1;i<=n;i++)
    {
        f[nown][0]=f[pre][0]+s[i];
        for(int j=1;j<=i;j++)
            f[nown][j]=min(f[pre][j-1]+p[i]+(i-j)*c,f[pre][j]+s[i]);
        nown=1-nown;pre=1-pre;
    }
    ll ans=INF;
    for(int i=0;i<=n;i++)
        ans=min(ans,f[pre][i]);
    cout<<ans;
    return 0;
}

4.有一个数字游戏,一开始有两个数1 1,然后每次可以选择其中一个数变成两个数的和。给定最后的状态n,m(<=10^18),求最少已经玩了多少次。

题解:求gcd,gcd是1的时候有解,答案是辗转相除的步数。

这道题居然还有负数,被坑了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 

ll ans=-1;

ll gcd(ll x,ll y)
{
    if(x<y) {ll t=x;x=y;y=t;}
    if(y==0)return x;ans+=x/y;
    return gcd(y,x%y);
}

int main()
{
    freopen("math.in","r",stdin);
    freopen("math.out","w",stdout);
    ll x=read(),y=read();
    if(x<=0||y<=0) return 0*puts("-1");
    if(gcd(x,y)!=1)puts("-1");
    else printf("%I64d\n",ans);
    return 0;
}

 

posted @ 2017-03-05 14:36  FallDream  阅读(179)  评论(0编辑  收藏  举报