X 和 Y 各有一个权值 vx,vy.
现在从最低位开始依次比较。
比如 vx=37,vy=28:
- 首先比较最后一位,(7,8),Y 暂时领先。
- 再加上前一位,(37,28),X 暂时领先。
- 比较结束。
如果我们用 X
代表小 X 暂时领先,Y
代表小 Y 暂时领先,那么可以写下一个字符串 XY
。
再比如,vx=137,vy=47。
如果我们再用 Z
表示小 X 与小 Y 的点赞数暂时一样,那么写下的字符串应该为 XYZ
。
给定最后的字符串 si,请构造一种可能的 (vxvy)。
若不存在构造方案,输出 −1.
为了方便输出,用前导零补足位数。
对于 100% 的数据,si∈{X,Y,Z},1≤len(s)≤106。
ZZZZZZ
000000
000000
plaintext
如果 Z 不是连续的后缀,则无解。
否则用 0/1 构造即可。
const int MAXN = 1e6 + 10;
string s;
int a[MAXN], b[MAXN];
int main() {
cin >> s;
int n = s.length(), flag = 0;
for(int i = 0; i < n; i++) {
if(flag && s[i] != 'Z') {
cout << -1 << endl;
return 0;
}
if(s[i] == 'X') a[i] = 1, b[i] = 0;
else if(s[i] == 'Y') a[i] = 0, b[i] = 1;
else if(s[i] == 'Z') flag = 1;
}
for(int i = 0; i < n; i++) cout << a[i]; cout << endl;
for(int i = 0; i < n; i++) cout << b[i]; cout << endl;
return 0;
}
cpp
给定正整数 n,请找出一个合法的三元组 (x,y,z),满足:
x1+y1+z1=n2
要求:x,y,z∈Z+ 且互不相同。
1≤n≤104.
x1+y1+z1=n1+n1
那就直接 z=n,则有:
x1+y1=n1
考虑裂项公式:
n1−n+11=n(n+1)1
因此:
x1+y1=n+11+n(n+1)1
于是得到:
⎩⎨⎧x=n+1y=n(n+1)z=n
当 n=1 时,x=y=n+1,无解。
否则,按上述方案构造即可。
给定一个长度为 n 的数组 a。
你需要确定一个范围 [x,y],并将 a 数组分成 k 段,使得对于每一段,在范围 [x,y] 以内的不同元素个数大于在范围 [x,y] 以外的不同元素个数。
此处的 x,y 都是权值,不是下标。
请求出任意一组使得 (y−x) 最小的 x,y,并输出划分的方案。
数据范围:
- t 组数据,1⩽t⩽3×104。
- 1⩽k⩽n⩽2×105,∑n⩽2×105。
- 1⩽ai⩽n。
对于这道题,最根本的问题是最小化的 (y−x),而具体的形式是如何划分整个序列。
我们可以发现,如果同时考虑这两个问题,事情会变得非常复杂,难以下手。
所以我们不妨暂且扔下具体的形式,去考察最根本的问题。
**性质:**划分为 k 段时,在 [x,y] 内的数总体上至少要比在此区间以外的数多 k 个。
**证明:**每个段内至少多一个,一共多至少 k 个。
做法:
先将整个序列从小到大排序,然后用一个大小为 n−⌊2n−k⌋ 的滑动窗口去检测。
窗口两端的数就是 [x,y],取 (y−x) 的最小值即可确定 [x,y]。
推理一下可以发现,让每一段都多一个,可以使滑动窗口尽可能小,这样 (y−x) 也会相应更小,同时这样的一组 [x,y] 一定有可行的划分方案。
最后构造方案时也是每一段多一个就划开即可。
https://ac.nowcoder.com/acm/contest/11251/D ↗
小红想让你构造一个长度不超过 200000 的字符串,其中包含 k 个 red 子序列。你能帮帮她吗?
子序列的定义:在原串中必须按顺序,可以不连续。例如,reddd 有3个:reddd,reded,reded.
若无法构造,输出 −1,多解输出任意。
数据范围:0≤k≤1014.
考虑字符串:
rerererererere…
在第一个 re 后面加 x 个 d,可稳定增加 x 个子序列;
在第二个 re 后面加 x 个 d,可稳定增加 3x 个子序列;
以此类推,
在第 k 个 re 后面加 x 个 d,可稳定增加 2k⋅(k+1)x 个子序列。
于是把字符串长度缩小到 n31 级别,可以证明这样的长度一定小于 200000.
#include<bits/stdc++.h>
using namespace std;
int tong[101010];
int main(){
long long n,i,j,k,p;
cin>>n;
if(n==0)return cout<<"d",0;
for(i=1;i*i*i/6<=n;i++);
i--;
for(j=i;j>0;j--){
tong[j]+=n/(j*(j+1)/2);
n%=j*(j+1)/2;
}
for(j=1;j<=i;j++){
cout<<"re";
while(tong[j]--)cout<<"d";
}
}
cpp
Task1:试判断能否构造并构造一个长度为 n 的 1…n 的排列,满足其 n 个前缀和在模 n 的意义下互不相同。若存在,请给出一种构造方案。
Task2:试判断能否构造并构造一个长度为 n 的 1…n 的排列,满足其 n 个前缀积在模 n 的意义下互不相同。若存在,请给出一种构造方案。
测试点类型 1:10 分,满足 X=1,1≤n≤10。
测试点类型 2:40 分,满足 X=1,1≤n≤105。
测试点类型 3:10 分,满足 X=2,1≤n≤10。
测试点类型 4:40 分,满足 X=2,1≤n≤105。
样例输入 #1#
样例输出 #1#
2 8 7 6 5 4 3 2 1
plaintext
样例输入 #2#
样例输出 #2#
2 1 2 3 5 10 6 7 4 9 8 11
plaintext
设序列为 ai,分别讨论两个子任务。
Task1#
设 si=(j=1∑iai)modn,可以有如下发现:
- ∀l,r,sl≡sr(modn) 当且仅当 sr−sl−1≡0(modn). 因此不存在区间 [l,r] 的区间和是 n 的倍数。
- 当 ai=n 时,i=1.
- 若 2∤n 且 n=1,无解。
接下来对有解情况进行构造。
发现 n 必定为偶数,要想让 s 构成 modn 意义下的完全剩余系,考虑把所有偶数在模意义下取相反数。
也就是说,使:
s={0,1,−2,3,−4,5,⋯,n−1}
注意到,所有偶数的符号为负,再加上 n 变为正数后,仍为偶数,所以 s 仍然满足题意。
则有 ai 的通项公式:
ai={n−i+1,i−1,2∣i2∤i
注意 a1=n=0.
Task2#
设 si=(j=1∏iai)modn,可以有如下发现:
- ∀l,r,sl≡sr(modn) 当且仅当 sl−1sr≡0(modn). 因此不存在区间 [l,r] 的区间积是 n 的倍数。
- 当 ai=n 时,i=n.
- 当 ai=1 时,i=1.
- 当 n 为合数时(4 除外),n∣(n−1)!,所以 sn−1≡sn(modn),无合法方案。
因此序列开头为 1,末尾为 n,n 为质数,想到 si=i 是否可行?
下面在 si−1+1≡si(modn) 的情况下构造:
si−1+1si−1×(ai−1)ai≡si−1×ai≡1=inv(si−1)+1(modn)(modn)(modn)
于是可以从头开始递推完成构造。
给你 n 个整点和它们的坐标,现在给它们分成两组并两两连上边。
对于每条边,如果两端的点在:同一组则边为黄色,不同组则为蓝色。
现在让你给出任意一种分组方案,使得所有长度相同的边颜色相同。
保证存在合法方案。
2≤n≤103,∣xi∣,∣yi∣≤106.
将点分为黑色和白色两组。
考虑对格子黑白染色,坐标和为偶数的染为黑色。
一、若两种颜色的点都存在#
黄色边的边长平方一定是奇数,蓝色边的边长平方一定是偶数,满足题目条件。
直接按黑白颜色分组即可。
二、若只存在一种颜色的点#
不妨设只存在黑点,因为只有白点,就可以全部下移一格,转化为黑点。
如果所有点的两维坐标都是偶数,则可以直接 ÷2,但我们只保证了 2∣(x+y).
想要转化到让 (x+y) 既有奇数又有偶数,过程中不改变点之间的位置关系。
注意到 2∣(x+y)⇒2∣(x−y).
联想到坐标旋转公式:
{x′=xcosθ−ysinθy′=xsinθ+ycosθ
若旋转 45°,则有:
⎩⎨⎧x′=22x−22y=22(x−y)y′=22x+22y=22(x+y)
旋转和缩放都可以保证点间位置关系不变。我们只想看到整数,于是让:
⎩⎨⎧x′=2x−yy′=2x+y
这样进行若干次,最终一定会使黑白点均存在。
分为了黑白点就可以由之前的方法解决,否则继续递归。
递归的次数为 O(logA) 次,其中 A 为坐标值域大小。