给定n,m,给出长度为n的01串,每次向后移动一位,移动m-1次,最后求出这n+m-1位每一位的异或值成为密码。
给出密码,问长度为n的01串是怎样的。
2 < = n + m < = 1000000 2<=n+m<=1000000 2<=n+m<=1000000,保证有解
密码第 i i i位设为 a i a_i ai,原串第 i i i位设为 b i b_i bi
a 1 = b 1 a_1=b_1 a1=b1
a 2 = b 1 a_2=b_1 a2=b1^ b 2 b_2 b2
a 3 = b 1 a_3=b_1 a3=b1^ b 2 b_2 b2^ b 3 b_3 b3
a m = b 1 a_m=b_1 am=b1^ b 2 b_2 b2… b m − 1 b_{m-1} bm−1^ b m b_m bm
…
a n = b n − m + 1 a_n=b_{n-m+1} an=bn−m+1^ b n − m + 2 b_{n-m+2} bn−m+2… b n − 1 b_{n-1} bn−1^ b n b_n bn
上往下推即可推出前 n n n个 b i b_i bi
时间复杂度 O ( n ) O(n) O(n)
#include
#define N 1000005
using namespace std;
int a[N], c[N], n, m;
char s[N];
// 110, 000, 011, 101
int main()
{
scanf("%d %d", &n, &m);
scanf("%s", s + 1);
for (int i = 1; i <= n + m - 1; i++) a[i] = s[i] - '0';
int now = a[1]; c[1] = a[1];
printf("%d", a[1]);
for (int i = 2; i <= n; i++)
{
if (i > m) now ^= c[i - m];
c[i] = a[i] ^ now;
printf("%d", c[i]);
now ^= c[i];
}
return 0;
}
定义:若A和B是亲戚,B和C是亲戚,那么A和C也是亲戚。
有n个人,m次操作
给出n个人的名字分别是什么(如果出现多个人名字相同,则视为同一个人)(保证姓名是小写字符串)
给出m个操作,每行操作给出一个数opt,两个名字x,y
当opt=1时,表示x,y是亲戚
当opt=2时,表示询问x,y是否是亲戚,若是输出1,不是输出0
1 < = n , m < = 20000 , 名 字 字 符 长 度 小 等 于 10 1<=n,m<=20000,名字字符长度小等于10 1<=n,m<=20000,名字字符长度小等于10
对于每个名字我们可以标记一个不同的 i d id id,然后就是一个裸的并查集,
i d id id可以通过排序去重以后得到,对于 x , y x,y x,y的 i d id id查询可以利用 l o w e r lower lower_ b o u n d bound bound
时间复杂度: O ( m l o g n ) O(mlogn) O(mlogn)
#include
#define N 20005
using namespace std;
int fa[N], n, m;
string s[N];
int find(int x)
{
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) cin >> s[i];
sort(s + 1, s + n + 1);
int tot = unique(s + 1, s + n + 1) - s - 1;
for (int i = 1; i <= tot; i++) fa[i] = i;
for (int i = 1; i <= m; i++)
{
int opt; string x, y;
scanf("%d", &opt); cin >> x >> y;
int pos1 = lower_bound(s + 1, s + tot + 1, x) - s - 1;
int pos2 = lower_bound(s + 1, s + tot + 1, y) - s - 1;
if (opt == 1) fa[find(pos1)] = find(pos2);
else { if (find(pos1) == find(pos2)) printf("1\n"); else printf("0\n"); }
}
return 0;
}
有n根柱子,每根柱子都有一个高度和柱子上面鱼干的数量。
开始的时候可以选择站在任意一根柱子上,每次跳跃不限长度而且只能从左向右跳跃,但只能跳到高度与当前所站高度差绝对值小于等于m的柱子上。
问最多能吃到最多的鱼干(最终不一定要落在第n根柱子上)
1 < = n < = 200000 , 1 < = m < = 500 1<=n<=200000,1<=m<=500 1<=n<=200000,1<=m<=500
对于每根柱子的高度x和鱼干数量y,满足 1 < = x < = 1000000 , 1 < = x , y < = 1000000 1<=x<=1000000,1<=x, y<=1000000 1<=x<=1000000,1<=x,y<=1000000
设 d p i dp_i dpi表示最后落到了高度为 i i i的柱子时能获得的最多鱼干
然后从左到右枚举柱子,
对于当前的柱子 k k k,
d p x k = m a x ( d p x k , m a x ( d p x k − m , d p x k − m + 1 , . . . , d p x k + m − 1 , d p x k + m ) + y k dp_{x_k}=max(dp_{x_k},max(dp_{x_k-m},dp_{x_k-m+1},...,dp_{x_k+m-1},dp_{x_k+m})+y_k dpxk=max(dpxk,max(dpxk−m,dpxk−m+1,...,dpxk+m−1,dpxk+m)+yk)
然后 m a x ( d p x k − m , d p x k − m + 1 , . . . , d p x k + m − 1 , d p x k + m ) max(dp_{x_k-m},dp_{x_k-m+1},...,dp_{x_k+m-1},dp_{x_k+m}) max(dpxk−m,dpxk−m+1,...,dpxk+m−1,dpxk+m)可以用线段树维护
时间复杂度就是 O ( n l o g ( x m a x ) ) O(nlog(x_{max})) O(nlog(xmax))
注意一下可能的越界 x k − m < 0 x_k-m<0 xk−m<0或者 x k + m > x m a x x_k+m>x_{max} xk+m>xmax
#include
#define lson(x) x * 2
#define rson(x) x * 2 + 1
#define M 1000005
#define N 200005
using namespace std;
typedef long long ll;
struct Node { int x; ll y; }a[N];
ll dp[M], C[M*5];
int maxnum, n, m;
void change(int G, int l, int r, int num1, ll num2)
{
if (l == r) { C[G] = num2; return; }
int mid = (l + r) >> 1;
if (num1 <= mid) change(lson(G), l, mid, num1, num2);
else change(rson(G), mid + 1, r, num1, num2);
C[G] = max(C[lson(G)], C[rson(G)]);
}
ll Get_max(int G, int l, int r, int ll, int rr)
{
if (ll == l && rr == r) return C[G];
int mid = (l + r) >> 1;
if (rr <= mid) return Get_max(lson(G), l, mid, ll, rr);
if (ll > mid) return Get_max(rson(G), mid + 1, r, ll, rr);
if (ll <= mid && rr > mid) return max(Get_max(lson(G), l, mid, ll, mid), Get_max(rson(G), mid + 1, r, mid + 1, rr));
return 0;
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d %lld", &a[i].x, &a[i].y), maxnum = max(maxnum, a[i].x);
dp[a[1].x] = a[1].y;
change(1, 1, maxnum, a[1].x, a[1].y);
for (int i = 2; i <= n; i++)
{
ll now = Get_max(1, 1, maxnum, max(a[i].x - m, 1), min(a[i].x + m, maxnum)) + a[i].y;
if (now > dp[a[i].x]) dp[a[i].x] = now, change(1, 1, maxnum, a[i].x, dp[a[i].x]);
}
ll ans = 0;
for (int i = 1; i <= maxnum; i++) ans = max(ans, dp[i]);
printf("%lld\n", ans);
return 0;
}
给定n个城市,m条飞机航线,k次半价机会,1为DongDong家,n为萨摩耶家,每条单向边都有起点终点和机票价格(保证所有价格大于0),她可以k次使用半价折扣,求从1到n的最小花费。(若无法从1到n,输出-1)
保证所有价格均为偶数
n < = 10000 , m < = 50000 , k < = 10 , 0 < = w < = 1000000 n<=10000,m<=50000,k<=10,0<=w<=1000000 n<=10000,m<=50000,k<=10,0<=w<=1000000,数据可能有重边和自环
分层图最短路,
令 d i s i , j dis_{i,j} disi,j表示到城市 i i i,用了 j j j半价折扣所需要的最小花费
然后直接做 s p f a spfa spfa即可
理论复杂度 O ( n k l o g ( n k ) ) O(nklog(nk)) O(nklog(nk))
#include
#define N 10005
#define M 50005
using namespace std;
typedef long long ll;
struct Node { int To, nxt; ll w; }e[M];
struct Code { int u, v; ll w; }a[M];
int ls[N], n, m, K, cnt;
ll dis[N][11], inf = 0x7fffffff;
bool vis[N][11];
queue Q[2];
bool cmp(Code aa, Code bb)
{
if (aa.u == bb.u) return aa.v < bb.v;
return aa.u < bb.u;
}
void Addedge(int u, int v, ll w)
{
e[++cnt].To = v, e[cnt].w = w, e[cnt].nxt = ls[u], ls[u] = cnt;
}
void spfa()
{
for (int i = 1; i <= n; i++)
for (int j = 0; j <= K; j++) dis[i][j] = inf * 10;
Q[0].push(1); Q[1].push(0);
vis[1][0] = 1; dis[1][0] = 0;
while (Q[0].size())
{
int u = Q[0].front(); Q[0].pop();
int num = Q[1].front(); Q[1].pop();
for (int i = ls[u]; i; i = e[i].nxt)
{
if (dis[u][num] + e[i].w / 2 <= dis[e[i].To][num + 1] && num + 1 <= K)
{
dis[e[i].To][num + 1] = dis[u][num] + e[i].w / 2;
if (!vis[e[i].To][num + 1]) Q[0].push(e[i].To), Q[1].push(num + 1), vis[e[i].To][num + 1] = 1;
}
if (dis[u][num] + e[i].w <= dis[e[i].To][num])
{
dis[e[i].To][num] = dis[u][num] + e[i].w;
if (!vis[e[i].To][num]) Q[0].push(e[i].To), Q[1].push(num), vis[e[i].To][num] = 1;
}
}
vis[u][num] = 0;
}
}
int main()
{
scanf("%d %d %d", &n, &m, &K);
for (int i = 1; i <= m; i++) scanf("%d %d %lld", &a[i].u, &a[i].v, &a[i].w);
for (int i = 1; i <= m; i++)
if (a[i].u != a[i].v)
if (a[i].u != a[i - 1].u || a[i].v != a[i - 1].v) Addedge(a[i].u, a[i].v, a[i].w);
spfa();
ll ans = inf * 10;
for (int i = 0; i <= K; i++) ans = min(ans, dis[n][i]);
if (ans == inf * 10) printf("-1\n"); else printf("%lld\n", ans);
return 0;
}
给定一个n个点,n-1条边的树形图(视1号店为根),每个点有一个颜色,m个询问,每次询问以x为根的子树中有多少种不同的颜色。
2 < = n < = 100000 , 1 < = m , c o l o r < = n 2<=n<=100000,1<=m,color<=n 2<=n<=100000,1<=m,color<=n
设 a n s i ans_i ansi表示以x为根的子树中有多少种不同的颜色。
然后利用 s e t set set内元素的不重复性,
从下往上合并,
当前 x x x结点的 s e t set set的的大小即为 a n s x ans_x ansx
然后每个询问直接回答即可
#include
#define N 100005
using namespace std;
struct Node{ int To, nxt; }e[N*2];
int ans[N], col[N], ls[N], n, m, cnt;
void Addedge(int u, int v)
{
e[++cnt].To = v, e[cnt].nxt = ls[u], ls[u] = cnt;
e[++cnt].To = u, e[cnt].nxt = ls[v], ls[v] = cnt;
}
set dfs(int x, int y)
{
set a;
for (int i = ls[x]; i; i = e[i].nxt)
{
if (e[i].To == y) continue;
set b = dfs(e[i].To, x);
for (set::iterator j = b.begin(); j != b.end(); j++) a.insert(*j);
}
a.insert(col[x]);
ans[x] = a.size();
return a;
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &col[i]);
int u, v;
for (int i = 1; i < n; i++) scanf("%d %d", &u, &v), Addedge(u, v);
ans[1] = dfs(1, -1).size();
for (int i = 1; i <= m; i++)
{
int ask; scanf("%d", &ask); printf("%d\n", ans[ask]);
}
return 0;
}
待完成