时间还不错,不过身体好像越来越差了sad
给出一个长度为n的字符串,初始位置在m,接下来对这个串有4种操作,“上下左右”,上:把当前字符变成字典序的下一个字符,如果是‘z'则变成'a',下:把当前字符变成字典序的上一个字符,如果是'a'则变成'z',左:把位置向左移一位,如果到了字符串的第一个位置,则跳到最后一个位置,右:与左相反
样例解释:
8 3
aeabcaez ---> 6
右:当前指针指b aeabcaez 上:把b换成c aeaccaez 左:回到a aeaccaez 左:回到e aeaccaez 左:回到a aeaccaez 下:a变z zeaccaez 共6步变成回文串
解题思路:为了简化问题,我们只看串的一半,如果初始时的位置在串的右半部分,我们就找到它在左边的对称部分开始操作,简化问题嘛。。。
但是我们要证明在右边和在左边操作的代价是一样的,比如这样一个串asdfvpojl,v是对称轴,把j变成s和把s变成j的代价是一样的。。。总之。。。真的是一样的
然后现在有的串是asdf要把它变成目标串pojl假设现在初始位置在s只需要把s到需要改的字符的步数算出来,把现有字符变成目标字符所需的最小变换次数算出来,相加就是结果。(注意细节的处理)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char S[110000];
int A[110000];
int mindis(char a, char b) {
if (a > b) swap(a, b);
int dis_1 = b-a;
int dis_2 = a+26-b;
return min(dis_1, dis_2);
}
int main() {
int len, pos;
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
scanf("%d%d%s",&len,&pos,S);
pos--;
for (int i = 0; i < len; i++) {
if (S[i] != S[len-1-i])
A[i] = A[len-1-i] = mindis(S[i], S[len-1-i]);
}
//for (int i = 0; i < len/2; i++)
// printf("%d ", A[i]);
// printf("\n");
int mid = (len+1)/2-1;
//printf("mid:%d pos:%d\n", mid, pos);
if (pos >= mid) pos = len - 1 - pos;
//printf("new pos : %d\n", pos);
if (len%2==1) mid--;
int ll = 0, rr = pos, ans = 0;
for (int i = mid; i >= pos; i--) if(A[i] != 0) { rr = i; break; }
for (int i = 0; i <= mid; i++) if (A[i] != 0) {ll = i; break;}
//printf("l r%d %d\n", ll, rr);
for (int i = ll; i <= rr; i++)
if (A[i] != 0) ans += A[i];
if (ans==0) {printf("%d\n", ans); return 0;}
if (pos >= rr)
ans += pos-ll;
else if (pos <= ll)
ans += rr-pos;
else ans += 2*min(rr-pos, pos-ll) + max(rr-pos, pos-ll);
printf("%d\n", ans);
return 0;
}
我们把n个节点n-1条边的图形叫做树,现在给你一个数字d和一棵由n个节点组成的树,每个节点有值ai,我们称树上点的一个集合S是合法的如果这个集合S满足下面的条件:
1.S是非空的
2.S是联通的
3.max Su - min Sv <= d (u, v在S中)
你的任务是计算这棵树中有多少个合法的集合,模(int)1e9+7
1 4 2 1 3 2 1 2 1 3 3 4
{1},{2},{3},{4},{1,2},{1,3},{3,4}{2,3,4}这8个是 符合样例的情况
题解:(赤裸裸的题解代码⊙﹏⊙b),这题应该算是枚举,枚举每个点(1,2....n),并把这个点当做含有这个点的集合中权值的最小的点。然后我们以这个点为起点做深搜,搜索其他的点,当其它点的权值小于起点的时候,这个点是不符合条件的(我们已经设了起点的权值最小),当一个点的权值减去起点的权值大于d的时候,也是不符合条件的。当搜到的点的权值和起点相等但是标号小于起点标号的时候,也不把这个点计算在内,否则会计算两遍。排除了这些限制之后,用dp[k]来表示在第k个节点处有多少个满足条件的集合,那么dp[v] = dp[v]*(dp[u]+1)。。。再想想(ˇˍˇ),最后把所有的dp值加起来就是结果了,顺便取模.
#include <bits/stdc++.h>
using namespace std;
const int N = 2000+10;
const int MOD = (int)1e9+7;
int vis[N], dp[N], a[N];
vector<int>G[N];
int d, n;
void DFS(int v, int rt) {
vis[v] = 1, dp[v] = 1;
for (int i = 0; i < G[v].size(); i++) {
int u = G[v][i];
if (!vis[u]) {
if (a[u] < a[rt] || a[u] > a[rt] + d) continue;
if (a[u] == a[rt] && u < rt) continue; // if (a[u] == a[rt] && u > rt) continue;
DFS(u, rt);
dp[v] = ((long long)dp[v]*(dp[u]+1) )%MOD;
}
}
}
int main() {
//freopen("in.txt", "r", stdin);
cin >> d >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++)
dp[j] = 0, vis[j] = 0;
DFS(i, i);
ans += dp[i];
if (ans >= MOD) ans -= MOD;
}
cout << ans << endl;
return 0;
}
给出一个由n个数字构成的序列,把这个序列的元素分为3种:
1.ai不属于最长递增子序列
2.ai至少属于1个但不属于每个最长递增子序列
3.ai属于每个最长递增子序列
输出这个序列中的每个元素所属的类型
4
1 5 2 3 ------> 3 1 3 3
1 5 2 3的最长递增子序列只有 1 2 3,1仅属于它,5不属于它,2,3仅属于它(这个序列中只有一个最长递增子序列)
研究ing
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n,qL,qR;
int a[maxn];
int L[maxn],R[maxn],M[maxn*4];
bool ans[maxn];
int num[maxn];
void build(int x,int f,int t) {
M[x] = 0;
if (f == t) return;
int mid = f + t >> 1;
build(x<<1,f,mid); build((x<<1)+1,mid+1,t);
}
void insert(int x,int f,int t,int d) {
if (f == t) {
M[x] = max(M[x],d);
return;
}
int mid = f + t >> 1;
if (qL <= mid)
insert(x<<1,f,mid,d);
if (mid < qR)
insert((x<<1)+1,mid+1,t,d);
M[x] = max(M[x<<1],M[(x<<1)+1]);
}
int query(int x,int f,int t) {
if (qL <= f && t <= qR) return M[x];
int mid = f + t >> 1,ans = 0;
if (qL <= mid) ans = max(ans,query(x<<1,f,mid));
if (mid < qR) ans = max(ans,query((x<<1)+1,mid+1,t));
return ans;
}
int main() {
scanf("%d",&n);
int Tmax = 0,td = 0;
for (int i = 1;i <= n; i++) scanf("%d",&a[i]),Tmax = max(a[i],Tmax);
build(1,1,Tmax);
for (int i = 1;i <= n; i++) {
qL = 1;qR = a[i]-1;
L[i] = (qL <= qR ? query(1,1,Tmax):0)+1;
qL = qR = a[i];
insert(1,1,Tmax,L[i]);
td = max(td,L[i]);
}
build(1,1,Tmax);
for (int i = 1;i <= n; i++) {
qL = a[n-i+1]+1; qR = Tmax;
R[n-i+1] = (qL <= qR ? query(1,1,Tmax):0)+1;
qL = qR = a[n-i+1];
insert(1,1,Tmax,R[n-i+1]);
}
for (int i = 1;i <= n; i++) {
if (L[i] + R[i] == td+1) { ans[i] = true; num[L[i]]++; }
}
for (int i = 1;i <= n; i++)
if (!ans[i]) printf("1");
else if (num[L[i]] == 1) printf("3");
else printf("2");
printf("\n");
return 0;
}