【POJ 1012 模拟】

题目链接:http://poj.org/problem?id=1012

我们从点1开始编号,则初始情况一共有2*k个点

假设b为已经杀掉的人数,now为现在的起始位置,next为下一个杀掉人的编号,初始时,b=now=0

 

则第一步,next=(0+m-1)%(2k-0)+1,(减1取模后再加1,为了防止0的出现),编号为next的人被杀掉,注意,此时的now不是next,而是next-1!然后再循环找下去就行,next=(now+m-1)%(2*k-b),由于不需要知道被杀掉的人原来的编号,杀掉这个人后,我们可以把整个环的数量减1,而所有坏人和好人都是还是各自连在一起的,所以不会有影响

 

后来看了discuss后,经牛人点拨,得知m必定为k+1的整数倍或者k+1的整数倍加1,为什么呢?考虑只剩下两个坏人时,他们此时的编号为k+1和k+2,如果杀掉的是k+1,那么走m=n*(k+1)+1步后可以杀掉原来编号为k+2的人,而如果先杀掉的是原来编号为k+2的,那么走m=n*(k+1)步后可以杀掉原来编号为k+1的人。这个解释太精彩了!这样优化后,可以从200多ms跑到100ms左右

 

总结:做题就是这样的,先从最笨的方法开始,然后在此基础上进行优化,另外,对于一些规律性的东西,可以从特殊情况或者最简单的情况去挖掘信息!还有,这题有很多组测试数据,但最多13种情况,我们可以将某种情况算出来的结果保存下来,下次再测试时直接输出!

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[100];
bool go(int m,int k){
    int cnt=0,now=0,next,b=0;
    while(true){
        next=(now+m-1)%(2*k-b)+1;
        if(next<=k)
            return false;
        else{
            now=next-1;
            b++;
            if(b==k)
                return true;
        }
    }
}
int main(){
    int k;
    while(~scanf("%d",&k)){
            if(!k)
                break;
            if(f[k]){
                printf("%d\n",f[k]);
                continue;
            }
            int i;
            for( i=k+1;;i++){
                if(i%(k+1)>1)
                    continue;
                if(go(i,k))
                    break;
            }
            f[k]=i;
            printf("%d\n",i);
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

paidream

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值