热身赛的1003,,水题啊,可是我折腾了一天。
首先要先发一次牌,得到一个顺序,再根据这个顺序获得各个循环节的长度,对循环节求最小公倍数,便是总的最少移动次数.
题意是,n张牌每次发给k个人,再堆叠起来重新发:比如样例 10 3
原始状态是: 1 2 3 4 5 6 7 8 9 10
一次过后: 10 7 4 1 8 5 2 9 6 3
第二次 3 2 1 10 9 8 7 6 5 4
第三次 4 7 10 3 6 9 2 5 8 1
第四次 1 2 3 4 5 6 7 8 9 10
根据做上一题的经验我们知道只要第一次的牌,我们可以求得循环节,再根据循环节长度就可以做出了.
怎么模拟出第一次洗牌后的序列呢?
把
1 2 3
4 5 6
7 8 9
10 11 12
然后每次取一列.\
T_T,我卡在了最后求最小公倍数上了,我是先乘了再除了的,问了群神就醒悟过来"这样会溢出"改成先除再乘,马上就过了^_^
1 2 3 4 5 6 7 8 9 10用二维数组这样存起来:
/*
Problem ID:hdu 4259
Meaning:
Analyzing:置换群+lcm(循环节长度)
*/
#include <iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
using namespace std;
typedef struct even{int y1,y2,x;}even;
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define LL long long
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 808
int A[maxn][maxn],V[maxn];
LL gcd(LL a,LL b) {return a?gcd(b%a,a):b;}
int main(){
int n,k;
while(~scanf("%d%d",&n,&k)&&(n||k)){
int cnt=1,i;
for(i=0;;i++){
for(int j=0;j<k;j++)
A[i][j]=cnt++;
if(cnt>n) break;
}
int M=1;
for(int j=0;j<k;j++){
for(int m=i;m>=0;m--){
if(A[m][j]<=n&&A[m][j])
V[M++]=A[m][j];
}
}
int vis[maxn];
LL res=1,len;
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++){
if(!vis[i]){
len=0;
int t=i;
while(1){
if(vis[t]) break;
len++;
vis[t]=1;
t=V[t];
}
res=res/gcd(len,res)*len;
}
}
printf("%I64d\n",res);
}
return 0;
}
再贴下标程,很赞0.0
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
long long gcd(long long a, long long b) { return a ? gcd(b % a, a) : b; }
int A[1010];
bool vis[1010];
int main() {
int N, K;
for(cin >> N >> K; N || K; cin >> N >> K) {
/* Compute the permutation induced by the shuffle. */
int M = 0;
for(int i = 0; i < K && i < N; i++) {
for(int j = (N - i - 1) / K * K + i; j >= 0; j -= K) {
A[M++] = j;
cout<<M-1<<" --> "<<A[M-1]<<endl;
}
}
/* Compute the lcm of the cycle lengths of the permutation. */
long long res = 1;
memset(vis, 0, sizeof(vis));
for(int i = 0; i < N; i++) {
int x = i;
int ln = 0;
while(!vis[x]) {
vis[x] = true;
x = A[x];
ln++;
}
/* Careful to divide then multiply here. */
if(ln) res = res / gcd(res, ln) * ln;
}
cout << res << endl;
}
}