T1
题意
给出,求形如的有序数对使得且均为质数。
题解
考场上我就写了,然后过掉了。
然后发现内的质数大概只有个,然后加起来的和的质数对是可以枚举的。所以直接先预处理每个数等于两个质数加起来的方案,然后枚举前两个数的和,乘上等于后两个数的和的方案,最后全部加起来就是了。
放上的代码
CODE
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long double ld;
typedef double db;
const int MAXN = 100005;
const db Pi = acos(-1.0);
int p[MAXN/10], cnt;
bool vis[MAXN];
void pre(int N) {
for(int i = 2; i <= N; ++i) {
if(!vis[i]) p[++cnt] = i;
for(int j = 1; j <= cnt && i*p[j] <= N; ++j) {
vis[i*p[j]] = 1;
if(i % p[j] == 0) break;
}
}
}
const int MAXL = (1<<18)+5;
struct cp {
db x, y;
cp(){}
cp(db x, db y):x(x), y(y){}
inline cp operator +(const cp &o)const { return cp(x+o.x, y+o.y); }
inline cp operator -(const cp &o)const { return cp(x-o.x, y-o.y); }
inline cp operator *(const cp &o)const { return cp(x*o.x - y*o.y, x*o.y + o.x*y); }
}f[MAXL], tmp[2][19][MAXL/2];
int rv[MAXL];
inline void FFT(cp* arr, const int &n, const int &flg) {
for(register int i = 0; i < n; ++i) if(i < rv[i]) swap(arr[i], arr[rv[i]]);
static cp t;
for(register int i = 2, p = 1; i <= n; i<<=1, ++p) {
for(register int j = 0; j < n; j+=i) {
for(register int k = j, q = 0; k < j+i/2; ++k, ++q) {
t = arr[k + i/2] * tmp[flg][p][q];
arr[k + i/2] = arr[k] - t;
arr[k] = arr[k] + t;
}
}
}
if(!flg) for(register int i = 0; i < n; ++i) arr[i].x /= n;
}
int nn[15];
int main () {
freopen("plus.in", "r", stdin);
freopen("plus.out", "w", stdout);
int n = 0, T;
scanf("%d", &T);
for(int i = 1; i <= T; ++i)
scanf("%d", &nn[i]), n = max(n, nn[i]);
pre(n);
for(int i = 1; i <= cnt; ++i) f[p[i]] = cp(1, 0);
int len = 1; while(len <= (n<<1)) len<<=1;
for(int i = 1; i < len; ++i)
rv[i] = (rv[i>>1]>>1)|((i&1)*(len>>1));
for(int i = 1; i <= 18; ++i) {
cp w1 = cp(cos(2*Pi/(1<<i)), sin(2*Pi/(1<<i)));
cp w0 = cp(cos(-2*Pi/(1<<i)), sin(-2*Pi/(1<<i)));
tmp[1][i][0] = tmp[0][i][0] = cp(1, 0);
for(int j = 1; j <= (1<<17); ++j)
tmp[1][i][j] = tmp[1][i][j-1] * w1,
tmp[0][i][j] = tmp[0][i][j-1] * w0;
}
FFT(f, len, 1);
for(int i = 0; i < len; ++i) f[i] = f[i] * f[i];
FFT(f, len, 0);
for(int i = 1; i <= n; ++i) f[i] = cp(round(f[i].x), 0);
for(int i = n+1; i < len; ++i) f[i] = cp(0, 0);
FFT(f, len, 1);
for(int i = 0; i < len; ++i) f[i] = f[i] * f[i];
FFT(f, len, 0);
for(int i = 1; i <= T; ++i)
printf("%lld
", (long long)(round(f[nn[i]].x)));
}
T2
题意
假设给定了两个整数 。有 个互不相同的整数 。对于每一个属于 到 的 y,我们找到 使得 异或 有最大值。即对于任意的 ,有 。(其中表示二进制异或)。
现在我们把这个问题反过来。给定 和 ,以及序列 ,计算有多少个不同序列 可以通过上文描述的问题生成出序列 。两个序列是不同的当且仅当存在一个 i 使得两个序列中 是不同的。
答案对 取模。
题解
考虑分治。对于区间的所有考虑,这里的都要在范围内。
假设序列中既有最高位为的数,又有最高位为的数。那么的与的一定没有交集。因为他们的都是在对方的区间取得。那么就可以分治下去。方案就是和的答案乘起来。
另一种情况是序列中只有最高位为的或者只有最高位为的数。那么两边的一定是一一对应的。因为所有的最高位是一样的,不用考虑。所以由于一一对应,答案就是,因为最高位既可以是又可以是。这种情况的条件是,顺次一一相等。
边界就是时返回。因为相当于,下面的数只有一个选择。
考试时差点想到…没有发现第二种情况两边的一一对应。
CODE
#include <cstdio>
const int mod = 1e9 + 7;
const int MAXN = (1<<16)+5;
int n, m, s, p[MAXN]; bool vis[MAXN];
int solve(int l, int r) {
if(l == r) return 1;
int mid = (l + r) >> 1, re = 0;
bool flg = 1;
for(int i = l; i <= mid; ++i)
if(p[i] != p[mid+i-l+1]) { flg = 0; break; }
if(flg) re = (re + 2ll * solve(l, mid) % mod) % mod;
flg = 1;
for(int i = l; i <= mid; ++i) vis[p[i]] = 1;
for(int i = mid+1; i <= r; ++i) if(vis[p[i]]) { flg = 0; break; }
for(int i = l; i <= mid; ++i) vis[p[i]] = 0;
if(flg) re = (re + 1ll * solve(l, mid) * solve(mid+1, r) % mod) % mod;
return re;
}
int main () {
freopen("match.in", "r", stdin);
freopen("match.out", "w", stdout);
scanf("%d%d", &m, &n);
s = 1<<m;
for(int i = 1; i <= s; ++i) scanf("%d", &p[i]);
printf("%d
", solve(1, s));
}
T3
题意
一棵树,初始时所有边都是黑色。有两种操作:
- :求到路径上的黑边数量。
- :将到路径上所有边设为白边,然后把只有一个点在这条路径上的边设为黑边。
题解
以为写了分暴力,发现有的数据不符合题目描述(可能是题目描述不符合数据? ),然后就了…
正解比较巧妙,我们把操作看做把所有点染上一个新的颜色,一条边为白边当且仅当两个点颜色相同。然后我们树剖后只需要维护线段上不同颜色段数就行了。
CODE
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 200005;
const int MAXQ = 300005;
int n, fir[MAXN], to[MAXN<<1], nxt[MAXN<<1], cnt;
inline void link(int u, int v) {
to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt;
}
int fa[MAXN], dep[MAXN], son[MAXN], top[MAXN], dfn[MAXN], sz[MAXN];
int tmr;
void dfs1(int u, int ff) {
dep[u] = dep[fa[u]=ff] + (sz[u]=1);
for(int i = fir[u], v; i; i = nxt[i])
if((v=to[i]) != ff) {
dfs1(v, u), sz[u] += sz[v];
if(sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int tp) {
top[u] = tp;
dfn[u] = ++tmr;
if(son[u]) dfs2(son[u], tp);
for(int i = fir[u], v; i; i = nxt[i])
if((v=to[i]) != fa[u] && v != son[u])
dfs2(v, v);
}
struct seg {
int l, r, ans;
seg(){}
seg(int l, int r, int ans):l(l), r(r), ans(ans){}
inline seg operator !() const{
return seg(r, l, ans);
}
inline seg operator +(const seg &o)const {
if(!ans) return o;
if(!o.ans) return *this;
return (r^o.l) ? seg(l, o.r, ans + o.ans) : seg(l, o.r, ans + o.ans - 1);
}
}v[MAXN<<2];
int lz[MAXN<<2], now;
inline void upd(int i) { v[i] = v[i<<1] + v[i<<1|1]; }
inline void pd(int i) {
if(~lz[i]) {
lz[i<<1] = lz[i<<1|1] = lz[i];
v[i<<1] = v[i<<1|1] = seg(lz[i], lz[i], 1);
lz[i] = -1;
}
}
void build(int i, int l, int r) {
lz[i] = -1;
if(l == r) { v[i] = seg(l, l, 1); return; }
int mid = (l + r) >> 1;
build(i<<1, l, mid);
build(i<<1|1, mid+1, r);
upd(i);
}
void modify(int i, int l, int r, int x, int y, int z) {
if(x <= l && r <= y) { v[i] = seg(z, z, 1); lz[i] = z; return; }
pd(i);
int mid = (l + r) >> 1;
if(x <= mid) modify(i<<1, l, mid, x, y, z);
if(y > mid) modify(i<<1|1, mid+1, r, x, y, z);
upd(i);
}
seg query(int i, int l, int r, int x, int y) {
if(x <= l && r <= y) { return v[i]; }
pd(i);
int mid = (l + r) >> 1; seg re = seg(-1, -1, 0);
if(x <= mid) re = re + query(i<<1, l, mid, x, y);
if(y > mid) re = re + query(i<<1|1, mid+1, r, x, y);
upd(i);
return re;
}
inline void cover(int a, int b) {
++now;
while(top[a]^top[b]) {
if(dep[top[a]] > dep[top[b]]) modify(1, 1, n, dfn[top[a]], dfn[a], now), a = fa[top[a]];
else modify(1, 1, n, dfn[top[b]], dfn[b], now), b = fa[top[b]];
}
if(dep[a] > dep[b]) modify(1, 1, n, dfn[b], dfn[a], now);
else modify(1, 1, n, dfn[a], dfn[b], now);
}
inline int getans(int a, int b) {
seg L = seg(-1, -1, 0), R = seg(-1, -1, 0);
while(top[a]^top[b]) {
if(dep[top[a]] > dep[top[b]]) L = L + !query(1, 1, n, dfn[top[a]], dfn[a]), a = fa[top[a]];
else R = query(1, 1, n, dfn[top[b]], dfn[b]) + R, b = fa[top[b]];
}
if(dep[a] > dep[b]) L = L + !query(1, 1, n, dfn[b], dfn[a]) + R;
else L = L + query(1, 1, n, dfn[a], dfn[b]) + R;
return L.ans-1;
}
int main () {
freopen("colour.in", "r", stdin);
freopen("colour.out", "w", stdout);
scanf("%d", &n); now = n;
for(int i = 1, x, y; i < n; ++i)
scanf("%d%d", &x, &y), link(x, y);
dfs1(1, 0), dfs2(1, 1);
build(1, 1, n);
int q, op, a, b;
scanf("%d", &q);
while(q-->0) {
scanf("%d%d%d", &op, &a, &b);
if(op == 0) printf("%d
", getans(a, b));
else cover(a, b);
}
}