计蒜客掷标枪
题目链接:https://www.jisuanke.com/problem/T3778
题目要求你根据公式依次算出每个人的掷标枪的距离然后计算得分,得分=离当前标枪落点最近后落点和前落点的标枪的距离之和
准确来说是这样的:
让我们来计算得分;
这道题用暴力和set+二分都不行,6e6超了,后者的做法是o(nlogn)级别,只能过80%
正确的做法是双向链表维护(不得不说这道题真的给我好好上了一课)
参考代码:
1 //因为xi = (ai%n) + 1 ≤ n,即1 ≤ xi ≤ 6 × 10^6,可是使⽤桶进⾏计数排序,然后建⽴有序的双向链表, 2 //注意因为要找大于或小于的值,因此链表内重复的数字只加⼊⼀次。 3 //题⽬求解的是依次加⼊xi时,计算结果之和,因为链表是通过计数排序建⽴的, 4 //因此可以转变思路:从最后⼀个数开始逆序删除每个数,计算答案。 5 //因为要删除,需要快速找到每个数在双向链表中位置,因此在建⽴双向链表的时候让xi位于索引xi处。 6 //每次删除时,让桶中这个数字的次数减少1,当减少到0时,将该数从双向链表中删除。 7 //总体的时间复杂度:O(n) 8 9 #include<bits/stdc++.h> 10 using namespace std; 11 #define int long long 12 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);; 13 const int mod=1e9+7; 14 const int N=6e6+10; 15 int x[N],cnt[N]; 16 int nxt[N],pre[N]; 17 int n,B,A,C; 18 int a; 19 int tot,sum; 20 inline int read(){ 21 int s=0,w=1;char ch=getchar(); 22 while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();} 23 while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar(); 24 return s*w; 25 } 26 inline void write(int x) 27 { 28 if (x < 0) putchar('-'), x = -x; 29 if(x > 9) 30 write(x / 10); 31 putchar(x % 10 + '0'); 32 return; 33 } 34 signed main() 35 { 36 IOS; 37 freopen("javelin.in", "r", stdin); 38 freopen("javelin.out", "w", stdout); 39 //n=read(),A=read(),B=read(),C=read(),a=read(); 40 cin>>n>>A>>B>>C>>a; 41 x[1]=(a%n)+1; 42 cnt[x[1]]++; 43 for(int i=2;i<=n;i++) 44 { 45 a=(A*a%mod*a%mod+B*a%mod+C)%mod; 46 x[i]=(a%n)+1; 47 cnt[x[i]]++; 48 } 49 for(int i=0;i<N;i++) 50 { 51 if(cnt[i]) 52 { 53 nxt[tot]=i; 54 pre[i]=tot; 55 tot=i; 56 } 57 } 58 nxt[tot]=N-9; 59 pre[N-9]=tot;; 60 for(int i=n;i>=1;i--) 61 { 62 int id=x[i]; 63 if(nxt[id]!=N-9) 64 { 65 sum=(sum+nxt[id])%mod; 66 } 67 if(pre[id]!=0) 68 { 69 sum=(sum+pre[id])%mod; 70 } 71 cnt[id]--; 72 if(cnt[id]==0) 73 { 74 nxt[pre[id]]=nxt[id]; 75 pre[nxt[id]]=pre[id]; 76 } 77 } 78 cout<<sum<<endl; 79 return 0; 80 }
本文来自博客园,作者:江上舟摇,转载请注明原文链接:https://www.cnblogs.com/LQS-blog/p/17053378.html