目录
前言
题解
A - Edge Checker 2
题意
题解
代码
B - Longest Uncommon Prefix
题意
题解
代码
C - abc285_brutmhyhiizp
题意
题解
代码
D - Change Usernames
题意
题解1
代码1
题解2
代码2
关于我是一个爱装的人,没事就装。俗话说,装X遭雷劈,ABC285就被雷劈了。
一个二十分钟的题目做了一个小时,还吃了一发罚时。
废话不多说,进入正题。
一棵满二叉树如图所示。
给你a,b,问你a,b是否相连(a > b)
满二叉树有一个性质。
就是节点i的儿子是(2i)和 (2i + 1)
我们利用c++正常除法向下取整这个特点,得出:如果b / a == 2 那么输出“Yes”,否则输出“No”
因为如果b是2a+1,在c++中,直接除可以向下取整,所以,
如果b是2a,,
其余情况都不相连。
#include
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int n,m,k;
template
int rets(T x) {cout << x << endl; return 0;}
string s;
void init(){
}
signed main(){
init();
cin >> n >> m;
if (m / 2 == n) cout << "Yes" << endl;
else cout << "No" << endl;
return 0;
}
其实这题很简单,但是读题是个问题,否则我也不可能16min才A掉。
给你一个字符串,长度为n。
枚举l使得,s[i + l] < n 并且
按题意模拟就行。
#include
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
#define lowbit(x) ((x)&(-(x)))
#define mod 998244353
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int n,m,k;
template
int rets(T x) {cout << x << endl; return 0;}
char s[M];
void init(){
}
signed main(){
init();
cin >> n >> (s + 1);
for (int l = 1 ; l < n ; l ++) {
int ans = 0;
for (int i = 1 ; i + l <= n ; i ++) {
if (s[i] == s[i + l]) break;
ans = i;
}
cout << ans << endl;
}
return 0;
}
在atcoder王国里,有个问题,每个问题都编号依次为A,B,C……AA,AB,……,ZZ……
然后给你一个字符串,请问这是第几个问题。
如AAABB
设pro[i]表示从1到i的这个字符串的编号,例如:pro[2] = "AA"的编号。
观察发现
pro[1] = (s[0] - 'A' + 1) * =
pro[2] = pro[1] * 26 + (s[1] - 'A' + 1) = + 1 = 27
pro[3] = pro[2] * 26 + (s[2] - 'A' + 1) …… 以此类推。
所以,pro[i] = pro[i - 1] * 26 + (s[i - 1] - 'A' + 1)
但是,这里我们优化一下空间,倒着计算,类似于哈希。
// 伪代码
base = 1;
for i : s.size() - 1 to 0 then do
ans += (s[i] - 'A' + 1) * base;
base *= 26;
#include
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
#define lowbit(x) ((x)&(-(x)))
#define mod 998244353
#define all(s) s.begin(),s.end()
#define Mn(a,b,c) min(a,min(b,c))
#define Mx(a,b,c) max(a,max(b,c))
#define sq(x) ((x) * (x))
#define cub(x) ((x) * (x) * (x))
#define all(s) s.begin(),s.end()
#define e9 1000000000
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int n,m,k;
template
int rets(T x) {cout << x << endl; return 0;}
string s;
void init(){
}
signed main(){
init();
cin >> s;
int ans = 0 , base = 1;
for (int i = s.size() - 1 ; i >= 0 ; i --) {
ans += (s[i] - 'A' + 1) * base;
base *= 26;
}
cout << ans << endl;
return 0;
}
就是这道题!!!装X遭雷劈
有n个用户。每个用户都想改自己的名字从改成(吃饱了撑着没事干)
问你能不能在满足上面三个条件的情况下,把所有用户的名字改成他们想要的。
能输出“Yes”,否则输出“No”
乍一眼看,好像这是一道暴力改名字的题目,但是那样就会很复杂。
思考一下,
a 把名字改成 b , b 把名字改成 c
如果c把名字改成不是a或b的就可以了
a -> b ,b -> c
c不能-> a,也不能 -> b
这不是个有向图判环吗!
不会有向图判环的点这里,题解2.
设a把名字改成b就是a到b有一条单向边,如果存在环,那么在改的时候就会重复。
举个例子:
a -> b
b -> c
c -> d
d -> a
当,你把a改成b时,你会发现,重复了。所以在这之前,你必须把b改成c,又重复了,在此之前,你必须把c改成d,重复,在此之前,你必须把d改成a。完了,人麻了,死循环。
所以只要有环,就判“No”。
上代码!
#include
using namespace std;
#define int long long
#define endl "\n"
const int N = 2e5 + 5;
int n,k = 1;
vector G[N];
map mp;
int vis[N], ind[N];
queue Q;
int BFS() {
while (!Q.empty()) Q.pop();
for (int i = 1;i <= k-1; i++) if(ind[i] == 0) Q.push(i);
int cnt = Q.size();
while (!Q.empty()) {
int u = Q.front();
Q.pop();
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
ind[v] --;
if(ind[v] == 0) {
Q.push(v);
cnt++;
}
}
}
return cnt;
}
signed main() {
cin >> n;
for (int i = 0; i < n; i++) {
string u,v;
cin >> u >> v;
if (!mp[u]) mp[u] = k ++;
if (!mp[v]) mp[v] = k ++;
G[mp[u]].push_back(mp[v]);
ind[mp[v]]++;
}
cout << (BFS() == k - 1 ? "Yes" : "No") << endl;
return 0;
}
但是有的大佬不会有向图判环咋整?
别急,办法总是有的(就是因为这个,所以我才没用有向图判环,否则我20min就AC了。)
先假设这个图不全是环,那么他总是有一个名字不会被改。找到这个名字,开始我们的
DFS之旅!!!(不就是DFS,有什么好大惊小怪的)
首先,用vector存图,记录下每个人要改的名字,找到不改的名字,DFS。
DFS里面,如果这个名字被访问过,直接return false。
如果这个名字不会改,return true。
然后return DFS(他要改的名字)。
写完了,交一发!
AC!
oj表示:WA!你得意个啥。
为什么WA?
看到我们的条件没有?
那全是环呢?
当然随便找一个点就可以DFS了,验证一下就行了,反正都是false
再交一发!
AC!
为什么?为什么?上帝为什么这么要对待我!
这是一个疯子,我们不要理会他。
会不会有一种情况,他不是一个连通图。
唉,所以要从vis没有标记过的点开始遍历。
再交一发!
上帝保佑我AC。
嘿嘿,我就要把你交炸。
这真是个一本正经(sàng xīn bìng kuáng)的人。
还是那个问题:为什么会WA?
深入思考,你会发现连样例3你都过不去。为什么?
你有没有发现,你遍历的时候,如果,一个字符串遍历过了,会return false,
但是,如果你先从它开始,然后再有人想把他的名字改成这个字符串,就会return false,所以,我们要标记一下,计作vis2,如果vis2没有标记过,再遍历。
终于可以上AC Code了。
#include
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
#define lowbit(x) ((x)&(-(x)))
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int n,m,k;
template
int rets(T x) {cout << x << endl; return 0;}
string s;
struct Node {
string from,to;
}a[N];
map vis;
map vis1;
map > fa;
vector fir;
map vis2;
void init(){
}
bool DFS (string s) {
// cout << s << endl;
if (vis[s]) {return false;}
if (fa[s].size() == 0) return true;
vis[s] = 1;
return DFS(fa[s][0]);
}
signed main(){
init();
cin >> n;
for (int i = 1 ; i <= n ;i ++) {
cin >> a[i].from >> a[i].to;
vis2[a[i].to] = 1;
// cout << a[i].from << " " << a[i].to << endl;
fa[a[i].from].push_back(a[i].to);
// cout << a[i].from << " " << fa[a[i].from] << endl;
}
for (int i = 1 ; i <= n ;i ++) {
if (!vis[a[i].from] && !vis2[a[i].from]) {
// cout << i << endl;
bool t = DFS(a[i].from);
if (!t) return rets("No");
}
}
for (int i = 1 ; i <= n ;i ++) {
if (!vis[a[i].from]) {
// cout << i << endl;
bool t = DFS(a[i].from);
if (!t) return rets("No");
}
}
rets("Yes");
return 0;
}