zstu2018新生赛 p8
1416: 你听说过排序吗?
时间限制: 1 Sec 内存限制: 128 MB
提交: 22 解决: 9
[提交] [状态] [讨论版] [命题人:admin]
题目描述
TT最近对排序算法很感兴趣,
现在他碰到了一个排序题,
给出包含n个数字的数组,
现在有两种操作:
1:把1到x之间的数从小到大排序,
2:把1到x之间的数从大到小排序,
初始序列满足
a[i] = a[i-1]x+a[i-2]y+z;(i>=3);
现给出a[1],a[2],x,y,z;
q[1] = a[1]%n+1,q[2] = a[2]%n+1;
q[i] = (yq[i-1]+xq[i-2]+z)%n+1;(i>=3)
op[i] = q[i]%2+1;(i>=1);
(op[i] 为第i个操作的类型,q[i]为第i次操作的x);
输入
第一行:T(T<=30)T组
每组测试包含7个数字:a[1],a[2],x,y,z,n,q,(1<=a[1],a[2],x,y,z<=1e9; 0<=n,q<=1e5)数组包含n个数字,q次操作;
输出
ans = (a[1]*1+a[2]*2,a[n]*n)%1000000007,
样例输入
1
2 3 1 2 3 6 3
样例输出
806
提示
原始序列为:2 3 10 19 42 83
第一次操作为 2 3 ,10 3 2 19 42 83
第二次操作为 1 4 ,2 3 10 19 42 83
第三次操作为 2 3 ,10 3 2 19 42 83
来源/分类
2018浙江理工大学新生赛
初看以为要用什么数学知识做,后来发现这个鬼公式实在没有好变形的,a与q只能暴力求,这里数据很大,所以采取边求边取模。
a最后输出结果是mod1000000007的,所以边求边mod1000000007
p公式里含有mod n,所以边求边mod n
之后排序的过程很显然不能模拟,肯定的是当p[i]>pj时,我们无视第j个操作
因此我们需要进行的操作k属于{n,n0,n1,n2,…,nx}
(p[n]<p[n0]<p[n1]<p[n2]<…<p[nx],n>n0>n1>n2>,…,nx)
将p[k]组成一个新的队列queue
区间 [queue[i-1]+1,queue[i]]需要进行对应的排序操作
由题意,queue[i]为奇数降序,偶数升序
我们用l,r表示排序即时的位置左右区间
从后往前维护,用数组ffind标记代替交换操作,当使用l,r时将l,r更新
tips a[1]<a[2]不一定,需要特判。
and more tips 从这题我学会了 1ll的操作,防止计算中途数据爆掉,方便许多-_-
Code:
#include
#include
#define Mod 1000000007
using namespace std;
typedef long long ll;
int l,r,q[100001],ffind[100001],queue[100001],a[100001];
void give(int start,int end,int flag)
{
int i;
if(flag==1)
for(i=end;i>=start;i–) ffind[i]=(l++);
else
for(i=end;i>=start;i–) ffind[i]=(r–);
}
int main()
{
int t,x,y,z,n,qq,i;
cin>>t;
while(t–)
{
cin>>a[1]>>a[2]>>x>>y>>z>>n>>qq;
q[1]=a[1]%n+1; q[2]=a[2]%n+1;
for(i=3;i<=n;i++)
a[i]=(1lla[i-1]x+1lla[i-2]y+z)%Mod;
for(i=3;i<=qq;i++)
q[i]=(1llyq[i-1]+1llxq[i-2]+z)%n+1;
int len=0;
queue[++len]=q[qq];
for(i=qq-1;i>=1;i–)
if(q[i]>queue[len]) queue[++len]=q[i];
if(queue[len]>=2&&a[1]>a[2]) swap(a[1],a[2]);
l=1;r=queue[len];int shut=r;
ll sum=0;
for(i=r+1;i<=n;i++)
sum=(sum+1lla[i]i%Mod)%Mod;
while(len–)
give(queue[len]+1,queue[len+1],queue[len+1]%2);
for(i=1;i<=shut;i++)
sum=(sum+1lla[ffind[i]]*i%Mod)%Mod;
cout<<sum<<endl;
}
}