P4828 Nagisa loves Tomoya 解题报告
P4828 Nagisa loves Tomoya 解题报告
67
1. 原题 P4828 Nagisa loves Tomoya
题目描述
可爱的古河渚得到了一个序列。她定义一次操作为 将所有的 \(a_i\) 变为 \(a_i+a_{(i\ mod \ n+1)}\)
然后她会向你进行 \(Q\) 次询问,每次问你 \(x,y\) ,意义为在第 \(x\) 次操作后位置 $y $ 的元素是多少。
这个问题太简单了,我们的 Nagisa 轻易地就解决了这个问题。请问您能解决这个问题吗?
输入格式
一个整数 \(n\),表示序列的长度。
接下来一行 \(n\) 个整数,表示这个序列。
接下来一行一个整数 \(Q\),表示询问次数
接下来 \(Q\) 行,每行两个整数 \(x,y\),意义如题所示。
输出格式
共 \(Q\) 行,每行一个整数表示询问的答案,请注意对 \(998244353\) 取模。
输入输出样例 #1
输入 #1
5
1 2 3 4 5
2
1 2
2 2
输出 #1
5
12
说明/提示
对于\(30 \%\)的数据,满足:
\(1 \leq n \leq 100\)
\(1 \leq x \leq 100\)
\(1 \leq Q \leq 100\)
对于 \(50\%\) 的数据:
\(1\leq n \leq 100000\)
\(1 \leq x \leq 500\)
\(1 \leq Q \leq 100\)
对于 \(100 \%\) 的数据,满足
\(1 \leq n \leq 10^6\)
\(1 \leq a_i \leq 10^9\)
\(1 \leq x \leq 2000\)
\(1 \leq Q \leq 10^4\)
2. 题目概述
给个序列,下标从 \(1\) 开始,有个操作,使得 \(a_i = a_{(i \bmod n) + 1}(1 \le i \le n)\),\(q\) 个询问,对于每个询问,问 \(x\) 次操作后,第 \(y\) 个位置的数是多少
3. 题解
题目分析
我们可以想到打一个暴力,按询问的 \(x\) 排序,依此操作计算,这样最坏复杂度是 \(O(nQ)\) 的很明显会 T 于是我们拿到了 50pts :
暴力代码
50pts
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int N = 1e6 + 10;
const int mod = 998244353;
typedef long long LL;
int n;
int a[N];
struct Query{
int x, y, id;
}q[N];
bool cmp(Query a, Query b){
return a.x < b.x;
}
void modify(){
int tmp = a[1];
for(int i = 1 ; i < n ; i ++) a[i] = (a[i] + a[i + 1]) % mod;
a[n] = (a[n] + tmp) % mod;
}
int ans[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i = 1 ; i <= n ; i ++) cin>>a[i];
int t;
cin>>t;
for(int i = 1 ; i <= t ; i ++){cin>>q[i].x>>q[i].y;q[i].id = i;}
sort(q + 1, q + t + 1, cmp);
int op = 0;
for(int i = 1 ; i <= t ; i ++){
for(; op < q[i].x ; op ++) modify();
ans[q[i].id] = a[q[i].y];
}
for(int i = 1 ; i <= t ; i ++) cout<<ans[i]<<'\n';
return 0;
}
继续分析
这咋办啊,打假了...那就从头开始想,我们发现这些操作其实就是把每个数都 += 下一个数(到 \(n\) 时加第 \(1\) 个数,不断递推下去,那我们来打个表找找规律:
5
1 2 3 4 5
1
5 2
不进行操作时:\(a_2\)
一次操作时:\(a_2+a_3\)
两次操作时:\(a_2+a_3+a_3+a_4\)
三次操作时:\(a_2+a_3+a_3+a_3+a_4+a_4+a_4+a_5\)
...
初见端倪,我们写下来
我们把系数写下来
很好这是一个杨辉三角
那我们做出来了
算法过程
- 预处理 \(2000\) 层杨辉三角
- 每次遇到询问 \(x \space y\) 时,直接在第 \(x\) 层杨辉三角且在数组 \(a\) 的第 \(y\) 个位置向后推,推到 \(n\) 就回到 \(1\) 直到把这一层杨辉三角推完算出答案
代码示例
别忘了取模
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int N = 1e6 + 10;
const int M = 2010;
const int mod = 998244353;
typedef long long LL;
int t[M][M];
void init(int n){
t[0][1] = 1;
for(int i = 1 ; i <= n ; i ++){
for(int j = 1 ; j <= i + 1 ; j ++){
t[i][j] = (t[i - 1][j] + t[i - 1][j - 1]) % mod;
if(t[i][j] == 0) t[i][j] = 1;
}
}
}
int a[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
init(2000);
int n;
cin>>n;
for(int i = 1 ; i <= n ; i ++){
cin>>a[i];
}
int q;
cin>>q;
for(int i = 1 ; i <= q ; i ++){
int x, y;
cin>>x>>y;
int ans = 0;
for(int j = 1, pos = y ; j <= x + 1 ; j ++){
ans = (ans + a[pos] * t[x][j] % mod) % mod;
pos = pos % n + 1;
}
cout<<ans<<'\n';
}
return 0;
}

浙公网安备 33010602011771号