Gym 100463A Crossings 逆序对

本文介绍了一种使用树状数组解决特定排列交叉数计算问题的方法。针对给定的数学公式生成一系列数字,并通过树状数组高效地计算出这些数字中逆序对的数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Crossings

Time Limit: 20 Sec

Memory Limit: 256 MB

题目连接

http://codeforces.com/gym/100463

Description

Given a permutation P of {0, 1, ..., n − 1}, we define the crossing number of it as follows. Write the sequence 0, 1, 2, . . . , n − 1 from left to right above the sequence P(0), P(1), . . . , P(n − 1). Draw a straignt line from 0 in the top line to 0 in the bottom line, from 1 to 1, and so on. The crossing number of P is the number of pairs of lines that cross. For example, if n = 5 and P = [1, 3, 0, 2, 4], then the crossing number of P is 3, as shown in the figure below. !""""#""""""""""""&" In this problem a permutation will be specified by a tuple (n, a, b), where n is a prime and a and b are integers (1 ≤ a ≤ n − 1 and 0 ≤ b ≤ n − 1). We call this permutation Perm(n, a, b), and the ith element of it is a ∗ i + b mod n (with i in the range [0, n − 1]). So the example above is specified by Perm(5, 2, 1).

Input

There are several test cases in the input file. Each test case is specified by three space-separated numbers n, a, and b on a line. The prime n will be at most 1,000,000. The input is terminated with a line containing three zeros.

Output

For each case in the input print out the case number followed by the crossing number of the permutation. Follow the format in the example output.

Sample Input

5 2 1 19 12 7 0 0 0

Sample Output

Case 1: 3 Case 2: 77

HINT

 

题意

给你n个数,   第i-1个数等于(a*i+b)%n,问逆序对有多少

题解:

树状数组

代码

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <ctime>
 5 #include <iostream>
 6 #include <algorithm>
 7 #include <set>
 8 #include <vector>
 9 #include <queue>
10 #include <map>
11 #include <stack>
12 #define MOD 1000000007
13 #define maxn 32001
14 using namespace std;
15 typedef __int64 ll;
16 inline ll read()
17 {
18     ll x=0,f=1;
19     char ch=getchar();
20     while(ch<'0'||ch>'9')
21     {
22         if(ch=='-')f=-1;
23         ch=getchar();
24     }
25     while(ch>='0'&&ch<='9')
26     {
27         x=x*10+ch-'0';
28         ch=getchar();
29     }
30     return x*f;
31 }
32 //*******************************************************************
33 
34 struct ss
35 {
36     int v,index;
37 } in[1000005];
38 int c[1000005];
39 int a[1000005];
40 ll n;
41 bool cmp(ss s1,ss s2)
42 {
43     return s1.v<s2.v;
44 }
45 int lowbit(int x)
46 {
47     return x&(-x);
48 }
49 int getsum(int x)
50 {
51     int sum=0;
52     while(x>0)
53     {
54         sum+=c[x];
55         x-=lowbit(x);
56     }
57     return sum;
58 }
59 void update(int x,int value)
60 {
61     while(x<=n)
62     {
63         c[x]+=value;
64         x+=lowbit(x);
65     }
66 }
67 
68 int main()
69 {
70     ll x,y;
71     int oo=1;
72     while(scanf("%lld%lld%lld",&n,&x,&y)!=EOF)
73     {
74         if(n==0&&x==0&&y==0)break;
75         memset(c,0,sizeof(c));
76         for(int i=0; i<n; i++)
77         {
78             a[i+1]=(x*i+y)%n+1;
79         }
80         ll ans=0;
81         for(int i=1; i<=n; i++)
82         {
83             update(a[i],1);
84             ans+=i-getsum(a[i]);
85         }
86         printf("Case %d: ",oo++);
87         cout<<ans<<endl;
88     }
89 
90 
91     return 0;
92 }
View Code

 

转载于:https://www.cnblogs.com/zxhl/p/4665453.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值