现在的位置: 首页 > 综合 > 正文

UVA – 1452 (jump 约瑟夫变形,求后三位数)

2019年04月03日 ⁄ 综合 ⁄ 共 2259字 ⁄ 字号 评论关闭
要求最后一位数的话比较简单,直接 f[ n ] = (f[n-1 ] +k )%n;原因很简单,f[n]的第一个数的位置为k-1;去掉该元素剩下的从k开始重新编号记为0-n-2
则f[n-1]的解的位置应该是 (f[n-1]+k)%n即f[n]的解;
由于我用的比较笨的方法,求倒数第二个数和第三个数都是和第一个数一个思路,程序写的叫繁杂而且系数较大,for example ,求倒数第二个数的之后先确定前两个数字的位置
那么剩下的重排就是f[n-2]的解;然后在算出该解对应原n个数中的位置;
但是这样想的实现如下,先展示较笨的我写的第一版本;
#include <cstdio>
#include <map>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 500100;
int f[maxn],f2[maxn],f3[maxn];
int debug(int a,int b,int lim);
void get_num(int& t,int t1,int t2,int i,int k){
  int add = (k-1)%(i-2);
  if(t1 < t2){
      int first = i-1-t2+t1;
      if(add < first)
         t = (t2+1+add)%i;
      else t = (t2+1+1+add)%i;
  }
  else {
      int first = t1-t2-1;
      if(add < first)
        t = (t2+1+add)%i;
      else  t = (t2+1+1+add)%i;
  }
}
int main()
{
    int n,k;
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&k);
        f[1] = 0;
        for(int i=1;i<=n;i++) f[i]=(f[i-1]+k)%i;

        f2[2] = debug(2,k,1);
        f2[3] = debug(3,k,2);
        for(int i=4;i<=n;i++){
            int t1 = (k-1)%i;
            int t2 = (t1+1+(k-1)%(i-1))%i;
            int first;
            if(t1 < t2){
                first = i-1-t2+t1;
            } else first = t1-t2-1;
            if(f2[i-2] < first){
                  f2[i] = (f2[i-2]+t2+1)%i;
            }
            else f2[i] = (f2[i-2]+t2+2)%i;
        }
        f3[3] = debug(3,k,1);
        f3[4] = debug(4,k,2);
        f3[5] = debug(5,k,3);
        for(int i=6;i<=n;i++){
            int t1 = (k-1)%i;
            int t2 = (t1+1+(k-1)%(i-1))%i;
            int t3 ;
            get_num(t3,t1,t2,i,k);
            if(t1 > t2) swap(t1,t2);
            int first , second;
            if(t3 < t1){
                first = t1-t3-1;
                second = first + t2-t1-1;
            }
            else if(t3 < t2){
                first = t2 - t3 - 1;
                second = first + i-1-t2+t1;
            }
            else {
                first = i-1-t3+t1;
                second = first + t2-t1-1;
            }

            if(f3[i-3] < first)
                f3[i] = (f3[i-3]+t3+1)%i;
            else if(f3[i-3] < second)
                f3[i] = (f3[i-3]+t3+2)%i;
            else
                f3[i] = (f3[i-3]+t3+3)%i;
        }
        printf("%d %d %d\n",f3[n]+1,f2[n]+1,f[n]+1);
}
    return 0;
}
int debug(int u,int k,int lim){
   int a[100]={0};
   int i=-1,cou=0;
   while(1){
       for(int cnt=0;cnt<k;cnt++){
            i=(i+1)%u; while(a[i]) i=(i+1)%u;
            i=i%u;
       }
       a[i] = 1;
       cou++;
       if(cou==lim) return i;
   }
}

其实,求倒数第2,3,完全可以和第一个一样;比如,确定2时,先确定f【2】的解,然后继续使用f[ n ] = (f[ n-1 ] +m)%n解出即可;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
const int MAXN = 110;
int n, m;

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &n, &m);
        int ans1 = 0, ans2, ans3;
        for(int i=2; i<=n; ++i)
        {
            ans1 = (ans1+m) % i;
            if(i==2)
            {
                ans2 = !ans1;
            }
            else if(i==3)
            {
                ans2 = (ans2+m) % i;
                bool vis[3];
                memset(vis, 0, sizeof(vis));
                vis[ans1] = vis[ans2] = true;
                for(int j=0; j<3; ++j)if(!vis[j])
                    {
                        ans3 = j;
                        break;
                    }
            }
            else
            {
                ans2 = (ans2+m) % i;
                ans3 = (ans3+m) % i;
            }
        }
        printf("%d %d %d\n", ans3+1, ans2+1, ans1+1);
    }

    return 0;
}

抱歉!评论已关闭.