P2162 -- Zrn神犇之折纸游戏
时间限制:2000MS
内存限制:524288KB
Description
Zrn神犇最近喜欢上一款折纸游戏,因此他几乎每天都拿着一条悠长悠长又寂寥的纸带折来折去。其具体规则是这样的:
这是一个长度为N,宽度为1的纸条,从1开始写着连续的N个自然数。
1 | 2 | 3 | 4 | 5 | 6 | … | N |
如果它的长度为偶数,Zrn神犇则会很高兴,直接把它从左往右或从右往左对折。比如长度为6的纸条从左往右对折完就会是这样:
如果它的长度为质数,Zrn神犇则会觉得不太爽,他就只能把最左端的往右折或把最右端的往左折。比如长度为5的纸条从右往左折完会变成这样:
如果它的长度是合数,Zrn神犇则会找到它最小的质因数k,把它分成相同长度的k段,按折长度为k的纸条的方法处理。
Zrn神犇就一遍又一遍地按着这个方法折,最后把这个纸条折成了一个叠在一起的小方块。
下面演示长度为15,对折和长度为质数时均从右往左折的纸条的折法:(描述可能不大清楚,请见谅)
(长度为15)
(长度为10)
(长度为5)
(长度为4)
(长度为2)
(长度为1,目标状态)
Input Format
三个数n,p1,p2,n为纸条的长度,若p1=1,对折时从左往右折,若p1=2,对折时从右往左折;若p2=1,长度为质数时折最左端,若p2=2,长度为质数时折最右端。
Output Format
N行,每行一个整数,为1~n的一个排列,表示目标状态从上到下纸片的编号。
Sample Input
15 2 2
Sample Output
2 12 9 8 13 3 4 14 7 6 15 5 10 11 1
Hint
对于20%的数据,n≤40;
对于50%的数据,n≤1000;
对于100%的数据,n≤5000000。
【题解】本来一看模拟,被数据范围吓傻了
然后经过了WZT、CYX大聚聚的教导
终于明白了-这是一题双链表。
然后就按照题目操作一下
憋了半个多小时,发现素因子被我筛错了……
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX=5000010; 4 int n,p1,p2,pr[MAX],head[MAX],next[MAX][2]; 5 int bgn,end,len; 6 int main() { 7 scanf("%d%d%d",&n,&p1,&p2); 8 // p[i]: i的最大素数因子 9 // 如果i为素数,那么p[i]=i; 反之成立 10 for (int i=2;i<=n;++i) 11 if (pr[i]==0) { 12 pr[i]=i; 13 for (int j=i*2;j<=n;j+=i) 14 if(pr[j]==0)pr[j]=i; 15 } 16 bgn=1;end=len=n; 17 for (int i=1;i<=n;++i) 18 head[i]=i, next[i][0]=next[i][1]=0; 19 while(len!=1) { 20 int sxbk=len/pr[len]; 21 if (len&1?p2==1:p1==1) { 22 for (int j=bgn+sxbk-1,k=bgn+sxbk;j>=bgn;--j,++k) { 23 next[head[k]][k&1]=head[j]; 24 next[head[j]][j&1]=head[k]; 25 head[k]=j; 26 } 27 bgn+=sxbk; 28 } 29 else { 30 for (int j=end-sxbk+1,k=end-sxbk;j<=end;++j,--k) { 31 next[head[k]][k&1]=head[j]; 32 next[head[j]][j&1]=head[k]; 33 head[k]=j; 34 } 35 end-=sxbk; 36 } 37 len-=sxbk; 38 } 39 for (int i=head[bgn];i;i=next[i][head[bgn]&1]) 40 printf("%d ",i); 41 return 0; 42 }