zoj 3836 Circulation pipe


zoj 3836 Circulation pipe


题意:有L个盒子[0..L-1],每k秒在0号盒子放入一件物品,每一秒盒子里的物品向前移动一格,到最右边或最左边,物品反向运动,问最短多少时间内某个盒子中物品数量超过c。


分析 (1) 在a位置的物品满足运动时间为  (正向)a,a+T,a+2T,…  和(反向)T-a,2T-a,…  (T=2*l-2)。

 (2) 若有一物品正向运动到a位置,(这个物品一定是第一次到a位置最优),即有某个物品运动a时间运动至a位置。

            若其他在a盒子的物品的运动时间t,则(t-a)%k==0。

 (3) 基于(2)正向运动的物品 此时在a位置的有   t=a,a+T*k/gcd(T,k),a+2*T*k/gcd(T,k)…,

         反向运动的物品 此时在a 位置的有   t=b,b+T*k/gcd(T,k),b+2*T*k/gcd(T,k)…

 (4)(3)中的b是几呢,(1)中知 b=xT-a  且  (2)最后(b-a)%k==0  

   所以 ((xT-a)-a)%k==0 =>xT-yk==2a   中国剩余定理跑一下 (当然b可能无解 且 有隐含条件b>a)


 (5) 大于c个 那么最少要在第几秒 (b无解,或者a==0||a==l-1自行考虑)

          1个是a秒 

    2个是b秒,

  3个是a+T*k/gcd(T,k)秒

  4个是b+T*k/gcd(T,k)秒… 知道规律了

(6) 枚举每一个a位置求出这个位置出现大于c个球的最短时间,取最小的一个就可以了。



#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
int l,k,c;
int T;
int exgcd(int a,int b,int &x,int &y){
    int d=a;
    if(b!=0){
        d=exgcd(b,a%b,y,x);
        y-=(a/b)*x;
    }
    else{x=1;y=0;}
    return d;
}

long long f(int a){
    long long b=-a;
    int x,y;
    int d=exgcd(T,k,x,y);
    long long t=(T*k/d);
    
    if((2*a)%d!=0) b=-1;
    else{
        x=x*(2*a)/d;
        b=(long long)x*T-a;
        b=(b%t+t)%t;
        while(b<=a) b+=t;
    }
    
    if(b!=-1&&(b-a)%k!=0) while(1);
    if(b==-1||a==0||a==l-1) return (c-1)*t+a;
    if(c&1) return (c/2)*t+a;
    else return (c/2-1)*t+b;
}

void solve(){
    long long ans=1LL<<60;
    for(int i=0;i<l;i++){
        ans=min(ans,f(i));
    }
    printf("%lld\n",ans);
}
int main()
{
    while(scanf("%d%d%d",&l,&k,&c)!=EOF){
        if(l==1) {printf("%d\n",c*k);continue;}
        c++;
        T=2*(l-1);
        solve();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值