最后一个:针对 n 范围比较大的解析
0、在公式:ans=(ans+m)%i 的基础上...当i很大,ans 和 m 都比较小的时候(i>>ans 和 m)。ans 每次增加的其实是 m。而这个增加次数可以算出来。所以...
1、当 ans + m >= i 时,普通递推。
2、当 ans + m < i 时,设增加次数为 x 次(代码中为:step 变量)。满足 ans + x * m < i + x - 1。
Ps:之所以是 x - 1,是因为 ans + m < i,ans + m + (x-1) * m < i + x -1。
3、由 2 得:x < (i - ans - 1) / (m - 1);x = ceil((i - ans - 1) / (m - 1)) - 1。
4、由 3 得:ans += x * m,i += x。
5、但如果 i 增加的总次数 (i + x) > n 了,那么最终结果应增加 (n - i + 1) * m 次,而不是 i+x 次。
/
#include<bits/stdc++.h> #include<cmath> #define mem(a,b) memset(a,b,sizeof a) #define INF 0x3f3f3f3f using namespace std; typedef long long ll; int main() { ll n,m; while(~scanf("%lld%lld",&n,&m)) { /* 最后一个:针对n范围比较小的解决方案 */ // 编号从0开始 // int ans=0; // for(int i=2;i<=n;i++) // ans=(ans+m)%i; // printf("%d\n",ans); // 输出的是数组下标 /* 最后一个:针对n范围比较大的解决方案 HDU3089 */ // 编号从0开始 // ll ans=0,step=0; // if(m==1) ans=n-1; // else if(n==1) ans=0; // else // { // for(ll i=2;i<=n;) // { // if(ans+m<i) // { step=(i-1-ans)%(m-1)?(i-1-ans)/(m-1):(i-1-ans)/(m-1)-1; // 等价下面这行代码 // step=ceil((i-1-ans)*1.0/(m-1))-1; // if(i+step>n) // { // ans+=(n-i+1)*m; // (n-i+1)次 // break; // } // // ans+=step*m; // i+=step; // } // else // ans=(ans+m)%i++; // } // ans%=n; // } // // printf("%lld\n",ans+1); // 输出的是数组下标 /* 出列顺序:针对出列顺序解决方案O(n*m) */ // 编号从0开始 // int idx=0,cnt=1,pout=0,vis[n+10]; // mem(vis,0); // while(pout!=n) // out人数是否满 // { // if(1==vis[idx]) // 已out // { // idx=(idx+1)%n; // continue; // } // // if(cnt%m==0) // 准备out // { // vis[idx]=1; // pout++; // printf("%d\n",idx+1); // } // // idx=(idx+1)%n; // 继续报数 // cnt++; // } /* 针对出列顺序解决方案O(n*(logn)^2) */ // 待更新... } return 0; }