灰暗而空虚的景色β

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

题解:对操作进行分析,很容易知道,每个有效操作都是当前序列中最小的且最靠右的数,提取出这个数之后再在从这个数开始之后的序列中重复操作,直到找到队尾。此时b[i]数组保存了每个有效操作,a[b[i]]即为此操作的数组下标

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ling long
#define INF 0×3f3f3f3f  //0×7ffffff
#define EPS 1e-6
#define maxn 1000000+10
#define PI acos(-1.0)
using namespace std;
ll a[maxn],pop;
ll findmin(ll l,ll r)//找当前序列的靠右最小值
{
    ll min=(1e9)+10;
    pop=r;
    for(int i=r;i>=l;i--)
    {
        if(min>a[i]) {min=a[i];pop=i;}
    }
    return pop;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    long long n,p,t,q,res;
    long long b[maxn];
    while(cin>>t)
    {
        while(t--)
        {
            memset(b,0,sizeof(b));
            b[1]=1;
            ll min=(1e9)+10;
            p=2;res=0;
            cin>>n>>q;
            for(int i=1;i<=q;i++)
            {
                cin>>a[i];
                if(min>=a[i]) {min=a[i];b[1]=i;}
            }
            a[q+1]=n+1;//为了处理序列的最后一个数
            pop=b[1];
            while(pop<q)
                b[p++]=findmin(pop+1,q);
            b[p++]=q+1;
            for(int i=2;i<p;i++)
            {
                ll t=a[b[i]]-a[b[i-1]];
                if((t*(t+1))%6==0)//如果直接用公式:t*(t+1)*(2*t+1)/6 会溢出,需要分类讨论
                {
                    int temp = t*(t+1)/6%123456789;
                    res+=temp*((2*t+1)%123456789);
                    res%=123456789;
                }
                else if(t*(2*t+1)%6==0)
                {
                    int temp = t*(2*t+1)/6%123456789;
                    res+=temp*((t+1)%123456789);
                    res%=123456789;
                }
                else if((t+1)*(2*t+1)%6==0)
                {
                    int temp = (t+1)*(2*t+1)/6%123456789;
                    res+=temp * (t%123456789);
                    res%=123456789;
                }
            }
            cout<<res<<endl;
        }
    }
    return 0;
}

 

PS:处理平方和时,为了避免溢出,采用了分类讨论,但是能不能这么写:(((x*(x+1))%123456789)(x2+1)/6)%123456789
显然不可以,因为/和%不能换位置,如12/6%6 = = 2,12%6/6 = = 0;
还有就是要注意处理序列的最后一个数

发表评论,支持MarkDown语法