个球从左到右排成一列。开始时,从左往右的第个球上写着数字。
请执行个操作,第个操作如下:
求所有操作后的球上分别写的数字。详见输出格式。
令个球中从左往右的第个在所有操作结束后写的数,则按如下格式输出:
即将按顺序输出到一行,用空格隔开。
略,请自行前往AtCoder查看。
根据数据范围可得,本题只能使用时间复杂度不超过的算法。
因此,暴力模拟,即查找每个球对应的位置()肯定是行不通的。
但是很容易想到可以设置索引数组,使当时,。
这样,对于每一个操作,只需的时间复杂度就能找到出现的位置。
交换时注意同时交换一下和中的元素即可。总时间复杂度。
#include <cstdio>
#define maxn 200005
using namespace std;
inline void swap(int& x, int& y) { x ^= y ^= x ^= y; }
int pos[maxn], ans[maxn];
int main()
{
int n, q;
scanf("%d%d", &n, &q);
for(int i=1; i<=n; i++)
ans[i] = pos[i] = i;
while(q--)
{
int x;
scanf("%d", &x);
int p1 = pos[x];
int p2 = p1 == n? p1 - 1: p1 + 1;
swap(pos[x], pos[ans[p2]]);
swap(ans[p1], ans[p2]);
}
for(int i=1; i<=n; i++)
printf("%d ", ans[i]);
return 0;
}
当一个正整数满足以下条件时,我们称其为“与相似的”:
求不超过的“与相似的”的个数。
将答案输出为一个整数。
输出 | |
---|---|
看到数据范围后我们发现太大,不能盲目下手。
由可知,。
又因为是质数,且可得,。
因此,当最小时最大,所以。
这时,可以想到筛出质数表,并对于每个质数计算最大的,此时质数都能作为,因此将答案加上的质数数量即可。当时,退出循环,输出结果即可。
计算时可以使用二分查找或者双指针算法快速处理。
总时间复杂度大约在。
本代码使用双指针实现。
#include <cstdio>
#include <cmath>
#include <vector>
#define maxp 794000
using namespace std;
using LL = long long;
bool bad[maxp];
vector<int> primes;
inline LL pow3(LL x) { return x * x * x; }
int main()
{
bad[0] = bad[1] = true;
for(int i=2; i<maxp; i++)
if(!bad[i])
{
primes.push_back(i);
for(int j=i<<1; j<maxp; j+=i)
bad[j] = true;
}
LL n;
scanf("%lld", &n);
LL ans = 0LL;
for(int i=0, j=primes.size()-1; i<j; i++)
{
while(j >= 0 && primes[i] * pow3(primes[j]) > n) j --;
if(i >= j) break;
ans += j - i;
}
printf("%lld\n", ans);
return 0;
}
给定长度为的正整数序列和。
对于每个,给定两个正整数,回答如下格式的查询:
集合可以说成是序列排序并去重的结果,如序列对应的集合是。
5
1 2 3 4 5
1 2 2 4 3
7
1 1
2 2
2 3
3 3
4 4
4 5
5 5
Yes
Yes
Yes
No
No
Yes
No
本题做法很多。这里我们介绍使用哈希(Hash)的算法。
现在我们有一个很简单但明显错误的思路:
将和做一个前缀和,只计算不重复的元素,即
此时,只需判断和是否相等即可。时间复杂度为或。
构造hack数据也很简单,只需部分前缀和相等即可,如:
5
1 3 5 6 7
3 2 4 1 5
1
3 3
这样,因为,所以这样的程序会认为这是相等的序列,从而输出Yes
,但显然,因此答案为No
,程序错误。
现在考虑改进这个思路,使其不容易被hack,可以使用一个哈希函数:
其中一般取质数,即为对应的哈希值。(对取模是为了防止哈希值太大导致溢出)
显然,这样有一个很小的概率会产生哈希冲突(即不同的数得到相同的哈希值),但因为的取值太多,评测机没法针对性的hack,所以正常情况下都能通过(CF的Hack机制除外)。如果真担心有问题,可以采取双哈希,即对于一个,用两个不同的哈希函数计算哈希值,这样就几乎不可能出现哈希冲突了。
现在,前缀和变为:
还是按原来的思路,判断前缀和是否相等即可。
总时间复杂度为(unordered_set
/HashSet
)或(set
/TreeSet
)。
这里还是要提一点,就是使用哈希时有一个小技巧,即直接取(unsigned int
)或者(unsigned long long
),使整数自然溢出,省去了麻烦又耗时间的取模步骤。CodeForces
上还是建议取较大的质数(常用的有)作为,以免被hack导致丢分。
这里我用的哈希函数为,即。
#include <cstdio>
#include <unordered_set>
#define maxn 200005
using namespace std;
inline int read()
{
char c;
while((c = getchar()) < '0' || c > '9');
int res = c ^ 48;
while((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c ^ 48);
return res;
}
unsigned suma[maxn], sumb[maxn];
inline void hread(unsigned* psum, int n)
{
unordered_set<int> s;
for(int i=1, x; i<=n; i++)
{
psum[i] = psum[i - 1];
if(s.insert(x = read()).second)
psum[i] += x * unsigned(x + 93) * unsigned(x + 117);
}
}
int main()
{
int n = read();
hread(suma, n);
hread(sumb, n);
for(int q=read(); q--;)
puts(suma[read()] == sumb[read()]? "Yes": "No");
return 0;
}