3. 织女的考验
- 下面的代码看似很正确,但忽略了一个细节,下面判断是否有字母数量不同时,用abs(cnt[i]) == 1判断,这里忽略了abs(cnt[i]) 等于其他值的情况(YES和NO都存在)
#include <iostream>
#include <cstring>
using namespace std;int n;
int cnt[30];
bool check(string s, string t) {memset(cnt, 0, sizeof cnt);if (s.size() == 1) {return true;}for(int i = 0; i < s.size(); i++) {cnt[s[i] - 'a']++;cnt[t[i] - 'a']--;}int num = 0;for (int i = 0; i < 26; i++) {if (abs(cnt[i]) == 1) num++;if (num > 2) return false;}return true;
}
int main() {cin >> n;string s, t;while(n--) {cin >> s >> t;if (check(s, t)) cout << "YES" << endl;else cout << "NO" << endl;}return 0;
}
- 修改后的代码
- 猜想1: 用num += cnt[i]; 最后判断num是否等于0,来判断答案。
- 不能,因为所有长度相等的字符串都满足这条件。
- 猜想2:用num += abs(cnt[i]);最后用num是否大于0判断。
- 不能,满足题目的只有两种情况,(1)两个字符串字母数量都相同,(2) 有两个字母数量不同,且都相差1,一个相减结果-1一个1。
#include <iostream>
#include <cstring>
using namespace std;int n;
int cnt[30];
bool check(string s, string t) {memset(cnt, 0, sizeof cnt);if (s.size() == 1) {return true;}for(int i = 0; i < s.size(); i++) {cnt[s[i] - 'a']++;cnt[t[i] - 'a']--;}int num = 0;for (int i = 0; i < 26; i++) {num += abs(cnt[i]);if (num > 2) return false;}return true;
}
int main() {cin >> n;string s, t;while(n--) {cin >> s >> t;if (check(s, t)) cout << "YES" << endl;else cout << "NO" << endl;}return 0;
}
4. 仙男仙女
- 我第一次想到的是用前缀和来做,但是,没有考虑好内存问题(需要开int * 1e9)。还有,应该将pos的值维护完以后,求好前缀和以后,在计算ans。
#include <iostream>
using namespace std;
const int N = 1e5 + 01, M = 1e9 + 10;
int a[N], n, p[N], b[N];
int pos[M];int main()
{int ans = 0;cin >> n;for (int i = 1; i <= n; i++) {cin >> p[i];}for (int i = 1; i <= n; i++) {cin >> b[i];}for (int i= 1; i <= n; i++) {pos[p[i]]++;pos[i] += pos[i - 1];int l = max(0, i - b[i] - 1), r = min(n, i + b[i] + 1 );if ((pos[i - 1] - pos[l] == 0) && (pos[r] - pos[i] == 0)) {ans++;}}cout << ans;return 0;
}
- 换一种思路,可以直接用pair储存位置和距离,按位置排序,最后求ans。
#include<iostream>
#include<algorithm>using namespace std;
#define x first
#define y second
const int N = 1e5 + 10;
int n;
pair<int, int> pa[N];int main() {cin >> n;for (int i = 1; i <= n; i++) {cin >> pa[i].x;}for (int i = 1; i <= n; i++) cin >> pa[i].y;sort(pa + 1, pa + n + 1);int ans = 0;if (n > 1 && pa[1].x + pa[1].y < pa[2].x) ans++;if (n > 1 && pa[n].x - pa[n].y > pa[n-1].x) ans++;for (int i = 2; i < n; i++) {if (pa[i].x + pa[i].y < pa[i + 1].x && pa[i].x - pa[i].y > pa[i - 1].x) ans++;}cout << ans;return 0;
}
5. 牛郎的微信群
- 分析: n 最大 10^5所以最大复杂度只能是 O ( n l o g ( n ) ) O( n log(n) ) O(nlog(n))。
- 我想,构建一个树. f[i] = g[p1] + g[p2] …(其中,p1 p2 … 是与i直接相连的节点,f[i]表示与i距离为2的节点,g[p]表示与节点p距离为1的点)。ans = (f[1] + f[2] + … + f[n]) / 2;
- 需要注意的点,(1)e和ne的大小 (2) f[r] += g[t] - 1; 减一表示要减去他自己。
#include<iostream>
using namespace std;const int N = 2e5 + 10;
int n, ind = 0, h[N], e[N * 2], ne[N * 2], g[N], f[N];void add(int a, int b) {e[++ind] = b;ne[ind] = h[a];h[a] = ind;
}
int ans = 0;
bool bs[N];void dfs(int r) {bs[r] = true;// cout << r << " ";for (int i = h[r]; i; i = ne[i]) {int t = e[i];f[r] += g[t] - 1;if (bs[t]) continue;dfs(t);}
}int main() {cin >> n;int x, y;for (int i = 0; i < n - 1; i++) {cin >> x >> y;add(x, y);add(y, x);g[x]++;g[y]++;}dfs(1);for (int i = 1; i <= n; i++) {cout << f[i] << " ";}return 0;
}
6. 就别重逢
题意可抽象为:给你n和k,求用不小于k的任意个正整数组成和不大于n的排列(有顺序)有多少种?
分析:
看到这个问题的时候,第一个就想到的是用动态规划来做,公式推导如下。(其中, f [ i ] f[i] f[i]表示刚好达到亲密度 i i i有多少种方法)
f[i] = f[0 1 2 .. i - k]
f[i + 1] = f[0 1 2 3 .. i-k i+1-k] = f[i] + f[i+1-k];
f[i] = f[i-1] + f[i-k];
通过程序如下:(题目要求达到n有多少种变化,也就是将f[k] f[k+1] … f[n] 加起来)
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n, k;
LL f[N], p = 1e9 + 7;int main()
{cin >> n >> k;f[k] = 1;LL ans = 2;for (int i = k + 1; i <= n; i++) {f[i] = (f[i-1] + f[i-k]) % p;ans = (ans + f[i]) % p;}cout << ans;return 0;
}