3 条题解
-
4
首先我们考虑一个分的暴力做法:直接模拟轮,这个非常好写,复杂度。
另外有分是,我们考虑到,最多只关心个位置的答案,完全可以考虑对这个位置来模拟。
如果一个元素当前在第个位置,那么,如果是奇数,则会在下一轮走到第个位置上,如果是偶数,则会在下一轮走到第个位置上。那么我们显然可以在的时间得到答案。
另外还有分是,我们尝试用一开始的暴力算法去模拟,会发现一个重要的结论:最多经过不超过的轮数,整个序列就又回到了初始时候的。
那么,我们先模拟一下记录周期,用,然后直接模拟轮即可。
刚才的暴力做法给了我们很大的提示:其实位置之间是构成了一些环的。
比如的时候,位置会在每一轮变化到位置这些位置,我们直接把这个环找到,就可以随便怎样算出来任意一个数字经过任意轮数所对应的答案了。(这个做法在,每次询问的不一样的时候一样可以解决)。
当然,也可以算一下所有环环长的最小公倍数,那么所有的数字都有这么大的周期,直接用的算法那模拟轮即可。
#include<bits/stdc++.h> #define ll long long #define maxn 1000005 #define mod 998244353 using namespace std; int n,Q; ll T; int vis[maxn]; int main() { cin>>n; int zong=0; int lcm=1; for (int i=2;i<=n;i++) if (!vis[i]) { vis[i]=1; int now=i,cnt=0; while (true) { cnt++; if (now&1) now=(now+1)/2; else now=(n+1)/2+now/2; if (now==i) break; vis[now]=1; } lcm=lcm/__gcd(lcm,cnt)*cnt; } ll T,Q; cin>>T>>Q; T%=lcm; int now; while (Q--) { cin>>now; for (int i=1;i<=T;i++) { if (now&1) now=(now+1)/2; else now=(n+1)/2+now/2; } cout<<now<<" "; } cout<<endl; }
-
2
补一个 数据的代码。顺便还附带了打表的程序片段。
#include <bits/stdc++.h> #define int long long using namespace std; const int MAXN = 1000000; int n, T, Q; // 打表看看 namespace TEST { vector<int> a, b; void out() { int tim = 1; for (int i = 1; i <= n; i++) a.push_back(i); cout << tim++ << ": "; for (int x : a) cout << x << " "; cout << "\n"; while (T--) { b.clear(); for (int i = 0; i < n; i += 2) b.push_back(a[i]); for (int i = 1; i < n; i += 2) b.push_back(a[i]); a = b; cout << tim++ << ": "; for (int x : a) cout << x << " "; cout << "\n"; } } } int nxt[MAXN + 5]; bool vis[MAXN + 5]; vector<int> e[MAXN + 5]; int ans[MAXN + 5]; signed main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> T >> Q; // TEST::out(); int base = n / 2 + (n & 1); // 奇数数量 for (int i = 1; i <= n; i++) { if (i % 2 == 1) nxt[i] = 1 + i / 2; else nxt[i] = base + i / 2; } // 每个点入度出度都是 1,所以必然是形成了几个环,现在把每个环都找到存下来 // 存成 vector 之后方便一口气做一个 T 轮的轮换 for (int i = 1; i <= n; i++) { int now = i; while (!vis[now]) { vis[now] = true; e[i].push_back(now); now = nxt[now]; } } // getAns for (int i = 1; i <= n; i++) { if (e[i].empty()) continue; int siz = e[i].size(); for (int j = 0; j < e[i].size(); j++) ans[e[i][j]] = e[i][(j + T) % siz]; } // 输出 Q 次询问的答案 while (Q--) { int b; cin >> b; cout << ans[b] << " "; } return 0; }
-
0
因为本题Q <= 10,所以可以考虑对于每一次查询,记录初始位置,如果下一次查询的结果=已知初始位置,则找出循环节 下面是本人的代码,可能有多余,但已经AC
#include<bits/stdc++.h>
using namespace std;
const long long maxq = 100, maxn = 1e6 + 5; long long n, t, q, a[maxq], flag, sum[maxn], cnt, b, ans[maxn];
int main() { long long i, j, num = 1;
cin >> n >> t >> q; for(i = 1; i <= q; i++) { cin >> a[i]; } for(i = 1; i <= q; i++) { j = a[i]; b = t; cnt = 0; memset(sum, 0, sizeof(sum)); memset(ans, 0, sizeof(ans)); num = 1; while(1) { ans[num] = j; num++; sum[j]++; if(sum[j] == 2) { break; } else { cnt++; } if(j % 2 == 0) { j = j / 2 + (n + 1) / 2; } else { j = j / 2 + 1; } } b = b % cnt + 1; cout << ans[b] << " "; } return 0;
}
- 1
信息
- ID
- 1384
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 9
- 标签
- (无)
- 递交数
- 234
- 已通过
- 24
- 上传者