http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1009&cid=832
Problem Description
In the world line 1.048596%
“雪啊。”
“雪是红色的。”
像坏掉的复读机一样,梓川咲太只能把闪烁的思绪断断续续的说出来。
“这,是梦吧。”
从口中滑出的却是这样的话。
回过神的时候,天空即将被冰冷黑暗的天空吞没,而自己已经站在湘南台站附近的图书馆的门口。那是第一次遇见樱岛麻衣的地方,是一切的开端。
无所谓了,已经没有可以称为家而能回去的地方了。就在梓川咲太开始自暴自弃的躺在地上任由黑暗吞噬的时候。
眼前突然出现了穿着白大褂的年轻女子,在昏暗的路灯下,随风飘扬的似乎是红色的秀发。
“不要去轻易的改变过去。”开口便是这么难懂的话。
“打个比方,对于一个长度为n,所有元素都为0的数列。每次操作都选取一个位置,使得从这个位置往后都变成1,4,9,16...i^2 ”
“不可思议啊,为什么我一直在,为什么你们,一直在让我做这种数学题。”梓川咲太快濒临崩溃了。
“为了拯救樱岛麻衣和牧之原翔子。这样的理由够充分吗?”那位女子的一句话,让咲太的精神从深海下看到一束光。
“你能计算出经过这么多次操作以后变得面目全非的数列的和吗?”
“不可随便改变过去,就刚才那个比方来说,如果有很多次这样的操作,那么这个数列的和也很难计算吧。”
“可你现在就是面临这个问题哦。计算出那个数列的和,你一定能够知道答案。”这是只有拥有确信的心的人才能说出来的话。
“算出来以后呢。”梓川咲太还需要最后一块拼图。
“去找牧之原翔子吧,一切因她而始,也必定一切因她而终。”
时间的流动在慢慢的将咲太唤回现实。
“许多失败了的未来,无法挽回的过去,但是肯定在这之后,会有连接到......”
熟悉的话语再次传来。但话语的主人已经消失在夜空里。
Input
第一行输入一个数字T(T<=10)表示数据有多少组;
每一组数据第一行包含两个整数n(1<=n<=1e9),Q(Q<=5e4),分别表示数列的长度以及操作的个数。
接下来的Q个数按照操作的时间顺序给出每次操作选择的位置.
Output
输出一个数字表示这个数列的和,由于答案可能很大,所以你需要将答案mod 123456789。
Sample Input
1 3 2 3 1
Sample Output
14
思路:
这道题有多次询问,我们可以将询问都存起来,然后倒着执行,因为后一个操作会覆盖前面的操作因此,最后一个执行的一定没有被覆盖,而倒数第二个的操作,有两种可能一是在上一个操作的区间内部,那么我们就跳过这一次操作。二是他的操作区间比最后一次还要长,那么这次操作区间就是,从这次的起点开始,到上一次的中点结束。就这段区间的和,就可以借助公式了。
这里的数会很大,因此我们需要借助取余操作,一开始想的是求逆元,但是发现这里求不出逆元,后来经zxz大佬的提醒想起了另一种做法。就是可以用这个公式x/d%k=x%(d*k)/d。
ac代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<string.h>
#define ll long long
#define ull unsigned long long
#define mod 123456789
using namespace std;
ll cal(ll x)
{
return (((x*(x+1))%(mod*6)*(2*x+1))%(mod*6))/6;
}
int n;
int a[1010101],num[1010101];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int q,n;
scanf("%d%d",&n,&q);
for(int i=0;i<q;i++)
{
cin>>a[i];
}
ll ans=0,ed=n;
for(int i=q-1;i>=0;i--)
{
if(a[i]<ed)
{
ans=(ans+cal(ed-a[i]+1))%mod;
ed=a[i]-1;
}
}
cout<<ans%mod<<endl;
}
return 0;
}