nowCoder 再编号
n
n
n个人,每个人有一个编号
a
i
a_i
ai 。
定义对
a
a
a 的再编号为
a
′
a'
a′ ,满足
a
i
′
=
(
∑
j
=
1
n
a
j
)
−
a
i
a_i'=(\sum_{j=1}^na_j) - a_i
ai′=(∑j=1naj)−ai
现在有
m
m
m 次询问,每次给定
x
,
t
x,t
x,t ,表示询问经过
t
t
t 次再编号后第
x
x
x 个人的编号。
由于答案可能很大,所以对
1
0
9
+
7
10^9+7
109+7 取模。
输入描述:
第一行 2 个数 n , m n,m n,m ,表示人数和询问次数;
接下来一行 n n n 个数,表示 a i a_i ai;
接下来 m m m 行,每行 2 个数 x , t x,t x,t ,描述一次询问。
输出描述:
m m m 行,第 i i i 行 1 个数表示第 i i i 次询问的答案对 1 0 9 + 7 10^9+7 109+7取模的结果。
示例1
输入
4 3
1 2 3 4
1 0
2 2
4 1
输出
1
22
6
说明
初始编号:1 2 3 4
1 次再编号后:9 8 7 6
2 次再编号后:21 22 23 24
备注:
n n n ≤ 100000 , m m m ≤ 10000 , t t t ≤ 100000 , 1 ≤ a i a_i ai ≤ 1 0 9 10^9 109
AC代码
#include<iostream>
using namespace std;
using ll = long long;
const int N = 1e5 + 5, mod = 1e9 + 7;
int n, m, a[N], s[N];
ll sum;
int main(){
cin >> n >> m;//n个人问m次
for(int i = 1; i <= n; i++){
cin >> a[i];
sum = (sum + a[i]) % mod;//算出再编号公式的被减数
}
for(ll i = 1, j = 1; i < 1e5; i++){
s[i] = (j - s[i - 1] + mod) % mod;
j = (j*(n - 1)) % mod;
}
while(m--){
int x, t;
cin >> x >> t;
ll ans = sum * s[t];
if(t & 1) ans = (ans - a[x] + mod) % mod;//t为奇数
else ans = (ans + a[x] + mod) % mod;//t为偶数
cout << ans << endl;
}
return 0;
}
代码分析
初始编号:1 2 3 4 sum = 10
1 次再编号后:9 8 7 6 sum = 30
2 次再编号后:21 22 23 24 sum = 90
3次再编号后:69 68 67 66 sum = 270
4次再编号后:201 202 203 204 sum = 810
5次再编号后:539 538 537 536 sum = 2430
找每次编码后与第一次编码的规律
发现:
1.奇数次编号和偶数次编号尾号一致
⇒
\Rightarrow
⇒ 分奇偶讨论
2.每次编号后sum的值规律为
q
=
3
q=3
q=3的等比数列
总结
1.(k + mod) % mod可确保所得数为正
2. & 按位与操作:转换为二进制位后两个均为1才为1,其余都位0
3. int能存储的最大数:
2
31
−
1
2^{31}-1
231−1