nowCoder 再编号
nnn个人,每个人有一个编号aia_iai 。
定义对 aaa 的再编号为 a′a'a′ ,满足ai′=(∑j=1naj)−aia_i'=(\sum_{j=1}^na_j) - a_iai′=(∑j=1naj)−ai
现在有 mmm 次询问,每次给定 x,tx,tx,t ,表示询问经过 ttt 次再编号后第 xxx 个人的编号。
由于答案可能很大,所以对 109+710^9+7109+7 取模。
输入描述:
第一行 2 个数 n,mn,mn,m ,表示人数和询问次数;
接下来一行 nnn 个数,表示 aia_iai;
接下来 mmm 行,每行 2 个数 x,tx,tx,t ,描述一次询问。
输出描述:
mmm 行,第 iii 行 1 个数表示第 iii 次询问的答案对 109+710^9+7109+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
备注:
nnn ≤ 100000 , mmm ≤ 10000 , ttt ≤ 100000 , 1 ≤ aia_iai ≤ 10910^9109
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=3q=3q=3的等比数列
总结
1.(k + mod) % mod可确保所得数为正
2. & 按位与操作:转换为二进制位后两个均为1才为1,其余都位0
3. int能存储的最大数:231−12^{31}-1231−1