---------------------------------------------------
https://blog.csdn.net/qq_41608020/article/details/98942305
两个长度为n的数组a,b,规定数组 , a b数组之间可以任意改变位置。求最小字典序的c数组
首先给a b数组分别建立字典树,二进制取&运算,数位的值相同时合成的数字最小,所以dfs在树上跑就行。
这个地方有个坑点,在dfs时,只有在到达数字的末尾才加入数字,并且可以知道数字出现的次数,但是如果在最后判断末尾时判断数字出现次数是否大于0会超时,所以在dfs时就判断数字出现次数是否大于0。
#include
using namespace std;
#define ll long long
typedef vector Vi;
typedef vector VI;
typedef pair pii;
#define pb push_back
#define mk make_pair
#define sc scanf
#define pr printf
const int N = 1e5 + 10;
struct Trie
{
int nex[N * 30][2], cnt[N * 30];
bool end[N * 30];
int root, idx;
int newnode()
{
++idx;
memset(nex[idx], 0, sizeof(nex[idx]));
end[idx] = 0, cnt[idx] = 0;
return idx;
}
void init()
{
idx = 0;
root = newnode();
}
void insert(int x)
{
int p = root;
for (int i = 29; i >= 0; i--)
{
int c = 1 & (x >> i);
if (!nex[p][c])
{
nex[p][c] = newnode();
}
p = nex[p][c];
++cnt[p];
}
end[p] = 1;
}
}t1, t2;
int c1[N], c2[N];
vector ans;
void dfs(int rt1, int rt2, int x)
{
int e = min(t1.cnt[rt1], t2.cnt[rt2]);
t1.cnt[rt1] -= e, t2.cnt[rt2] -= e;
if (t1.end[rt1])
{
ans.pb(mk(x, e));
return;
}
if (t1.cnt[t1.nex[rt1][0]] && t2.cnt[t2.nex[rt2][0]])
dfs(t1.nex[rt1][0], t2.nex[rt2][0], x << 1);
if (t1.cnt[t1.nex[rt1][1]] && t2.cnt[t2.nex[rt2][1]])
dfs(t1.nex[rt1][1], t2.nex[rt2][1], x << 1);
if (t1.cnt[t1.nex[rt1][1]] && t2.cnt[t2.nex[rt2][0]])
dfs(t1.nex[rt1][1], t2.nex[rt2][0], x << 1 | 1);
if (t1.cnt[t1.nex[rt1][0]] && t2.cnt[t2.nex[rt2][1]])
dfs(t1.nex[rt1][0], t2.nex[rt2][1], x << 1 | 1);
}
int main()
{
int T;
sc("%d", &T);
while (T--)
{
ans.clear();
int n;
sc("%d", &n);
t1.init();
for (int i = 1; i <= n; i++)
{
sc("%d", &c1[i]);
t1.insert(c1[i]);
}
t2.init();
for (int i = 1; i <= n; i++)
{
sc("%d", &c2[i]);
t2.insert(c2[i]);
}
dfs(t1.root, t2.root, 0);
sort(ans.begin(), ans.end());
for (int i = 0; i < ans.size(); i++)
{
for (int j = 1; j <= ans[i].second; j++)
printf(j == ans[i].second ? "%d" : "%d ", ans[i].first);
if (i != ans.size() - 1)
printf(" ");
}
printf("\n");
}
}
/*
ababcababababcabab
*/
#include
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAX_NODE = 1e5 + 5;
const int qwe = 29;
struct Trie
{
int nex[2];
int val;
}a[MAX_NODE * 31], b[MAX_NODE * 31];
int cnt1, cnt2;
int ans[100005];
char s[32];
int n, t;
void init()
{
memset(a[0].nex, 0, sizeof(a[0].nex));
a[0].val = 0;
cnt1 = 1;
memset(b[0].nex, 0, sizeof(b[0].nex));
b[0].val = 0;
cnt2 = 1;
}
void insert(char* s, int infor, int op)
{
int len = qwe;
int u = 0;
if (op == 0)
{
for (int i = qwe; i >= 0; i--)
{
if (a[u].nex[s[i] - '0'] == 0)
{
memset(a[cnt1].nex, 0, sizeof(a[cnt1].nex));
a[cnt1].val = 0;
a[u].nex[s[i] - '0'] = cnt1++;
}
u = a[u].nex[s[i] - '0'];
a[u].val += infor;
}
}
else
{
for (int i = qwe; i >= 0; i--)
{
if (b[u].nex[s[i] - '0'] == 0)
{
memset(b[cnt2].nex, 0, sizeof(b[cnt2].nex));
b[cnt2].val = 0;
b[u].nex[s[i] - '0'] = cnt2++;
}
u = b[u].nex[s[i] - '0'];
b[u].val += infor;
}
}
}
void query()
{
for (int cas = 0; cas < n; cas++)
{
int w = 0;
int u1 = 0, u2 = 0;
for (int i = qwe; i >= 0; i--)
{
if (a[a[u1].nex[0]].val && b[b[u2].nex[0]].val)
{
u1 = a[u1].nex[0];
u2 = b[u2].nex[0];
a[u1].val--;
b[u2].val--;
}
else if (a[a[u1].nex[1]].val && b[b[u2].nex[1]].val)
{
u1 = a[u1].nex[1];
u2 = b[u2].nex[1];
a[u1].val--;
b[u2].val--;
}
else if (a[a[u1].nex[0]].val && b[b[u2].nex[1]].val)
{
u1 = a[u1].nex[0];
u2 = b[u2].nex[1];
a[u1].val--;
b[u2].val--;
w += 1 << i;
}
else if (a[a[u1].nex[1]].val && b[b[u2].nex[0]].val)
{
u1 = a[u1].nex[1];
u2 = b[u2].nex[0];
a[u1].val--;
b[u2].val--;
w += 1 << i;
}
}
ans[cas] = w;
}
}
int main()
{
//freopen("1.in", "r", stdin);
//freopen("ans.txt", "w", stdout);
int T;
sc("%d", &T);
while (T--)
{
init();
sc("%d", &n);
for (int i = 0; i < n; i++)
{
sc("%d", &t);
for (int j = 0; j <= qwe; j++)
{
if (t & (1 << j))
s[j] = '1';
else
s[j] = '0';
}
insert(s, 1, 0);
}
for (int i = 0; i < n; i++)
{
sc("%d", &t);
for (int j = 0; j <= qwe; j++)
{
if (t & (1 << j))
s[j] = '1';
else
s[j] = '0';
}
insert(s, 1, 1);
}
query();
sort(ans, ans + n);
for (int i = 0; i < n; i++)
printf("%d%c", ans[i], i == n - 1 ? '\n' : ' ');
}
}
有 n 个多项式 ,求 的所有解。
按照每个多项式的零点排序,然后依此枚举零点所在的范围,小于等于这个零点的多项式都是正数,否则就是负数。
特判一下无穷多解和无解的情况就可以了
#include
#define ll long long
#define sc scanf
#define pr printf
#define Pair pair
using namespace std;
const int MAXN = 1e5 + 5;
struct node
{
int a;
int b;
double chu;
}que[MAXN];
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
int main()
{
int T;
sc("%d", &T);
while (T--)
{
vectorv;
int n, C, len;
sc("%d%d", &n, &C);
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &que[i].a, &que[i].b);
que[i].chu = -(double)que[i].b / que[i].a;
}
sort(que + 1, que + n + 1, [](node q, node w) {
return q.chu < w.chu;
});
for (int i = 1; i <= n; i++)
{
que[i].a += que[i - 1].a;
que[i].b += que[i - 1].b;
}
for (int i = 0; i <= n; i++)//小于等于i的都是正数
{
// x = bb / aa
int aa = que[i].a - (que[n].a - que[i].a);
int bb = C - (que[i].b - (que[n].b - que[i].b));
if (aa == 0 && bb == 0)//无穷多解
{
printf("-1\n");
goto qwe;
}
else if (bb == 0)//唯一解
{
aa = 1;
}
else if (aa == 0)//无解
continue;
else//正常解
{
int g = gcd(aa, bb);
aa /= g, bb /= g;
}
if (aa < 0)//分母符号一定为正
{
aa = -aa;
bb = -bb;
}
//判ans范围
if (i == 0)
{
if ((double)bb / aa <= que[1].chu)
v.push_back(Pair{ bb,aa });
}
else if (i == n)
{
if ((double)bb / aa >= que[n].chu)
v.push_back(Pair{ bb,aa });
}
else
{
if ((double)bb / aa >= que[i].chu && (double)bb / aa <= que[i + 1].chu)
v.push_back(Pair{ bb,aa });
}
}
v.erase(unique(v.begin(), v.end()), v.end());
printf("%d", v.size());
len = v.size();
for (int i = 0; i < len; i++)
printf(" %d/%d", v[i].first, v[i].second);
printf("\n");
qwe:;
}
}
枚举最后8个数字全排列。
#include
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
int n, k;
struct node
{
int aa[10];
}que[50005];
int a[10];
int main()
{
int T;
sc("%d", &T);
while (T--)
{
sc("%d%d", &n, &k);
if (n >= 9)
{
printf("%d ", n);
for (int i = 1; i <= n - 9; i++)
printf("%d ", i);
for (int i = n - 8; i <= n - 1; i++)
a[i - (n - 8) + 1] = i;
int cnt = 0;
do {
for (int i = 1; i <= 8; i++)
que[cnt].aa[i] = a[i];
cnt++;
} while (next_permutation(a + 1, a + 1 + 8));
sort(que, que + cnt, [](node q, node w) {
for (int i = 1; i <= n; i++)
if (q.aa[i] - q.aa[i - 1] != w.aa[i] - w.aa[i - 1])
return q.aa[i] - q.aa[i - 1] < w.aa[i] - w.aa[i - 1];
});
for (int i = 1; i <= 8; i++)
pr("%d%c", que[k - 1].aa[i], i == 8 ? '\n' : ' ');
}
else
{
for (int i = 1; i <= n; i++)
a[i] = i;
int cnt = 0;
do {
for (int i = 1; i <= n; i++)
que[cnt].aa[i] = a[i];
cnt++;
} while (next_permutation(a + 1, a + 1 + n));
sort(que, que + cnt, [](node q, node w) {
for (int i = 2; i <= n; i++)
if (q.aa[i] - q.aa[i - 1] != w.aa[i] - w.aa[i - 1])
return q.aa[i] - q.aa[i - 1] < w.aa[i] - w.aa[i - 1];
});
for (int i = 1; i <= n; i++)
pr("%d%c", que[k - 1].aa[i], i == n ? '\n' : ' ');
}
}
}
exkmp模板题
#include
#define ll long long
#define sc scanf
#define pr printf
const ll mod = 998244353;
const int MAXN = 1e6 + 5;
using namespace std;
char x[MAXN];
int nex[MAXN];
int m;
void pre_EKMP() {
nex[0] = m;
int j = 0;
while (j + 1 < m && x[j] == x[j + 1])j++;
nex[1] = j;
int k = 1;
for (int i = 2; i < m; i++) {
int p = nex[k] + k - 1;
int L = nex[i - k];
if (i + L < p + 1)nex[i] = L;
else {
j = max(0, p - i + 1);
while (i + j < m && x[i + j] == x[j])j++;
nex[i] = j;
k = i;
}
}
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%s", x);
m = strlen(x);
pre_EKMP();
ll ans = 0;
for (int i = 1; i < m; i++)
{
ans += min(nex[i] + 1, m - i);
}
printf("%lld\n", ans);
}
}
有一个长度为 n 的排列,求左端点和右端点已经确定的方案数。每个询问三个数字 n l r,表示排序长度为 n ,左端点为 l,右端点为 r,的排列的方案数。
首先他们是先下降在上升的序列,并且只有区间中间是可以交换的,并且每个数字只能交换一次。
假设输入是 10 3 7,那么他只有开区间 是可以交换的,然后随便dp搞一下,
然后发现端点会使得区间长度加一,特判一下端点。
#include
#define ll long long
#define sc scanf
#define pr printf
const ll mod = 998244353;
using namespace std;
ll fib[100005];
int main()
{
fib[1] = 1;
fib[2] = 1;
fib[3] = 1;
for (int i = 4; i < 100005; i++)
fib[i] = (fib[i - 1] + fib[i - 3]) % mod;
int T;
sc("%d", &T);
while (T--)
{
int n, x, y;
sc("%d%d%d", &n, &x, &y);
int len = y - x - 1;
if (x == 1)
len++;
if (y == n)
len++;
ll ans = fib[len];
printf("%lld\n", ans);
}
}