1005:
二分题,题目不难,思路也简单清晰的,考的是细节
每个数首先如果刚好有我这个值,那么肯定直接拿,否则要靠前缀和拿多轮的话肯定是拿的轮数越少越好,那么就把模完以后相同的前缀放到一个\(vector\)里面,直接二分找到小于等于我的那个即可,负的情况就是大于等于我的那个。注意模0的情况。
#define int long long
const int maxn = 1e5 + 10, mod = 998244353;
map<int, int> mp, mp2;
int tot = 0;
struct node{
int x, y;
node(int x = 0, int y = 0) : x(x), y(y){}
bool operator < (const node &a) const {
return x < a.x;
}
};
vector<node> v[maxn];
int a[maxn];
void run() {
int n, m, pre = 0;
cin >> n >> m;
mp.clear();
mp2.clear();
tot = 0;
for(int i = 1; i <= n; ++ i) cin >> a[i], pre += a[i];
int sum = pre;
pre = 0;
if(sum == 0) {
mp2[0] = 0;
for(int i = 1; i <= n; ++ i) {
pre += a[i];
if(!mp2.count(pre)) mp2[pre] = i;
}
for(int i = 1; i <= m; ++ i) {
int x; cin >> x;
if(mp2.count(x)) cout << mp2[x] << '\n';
else cout << -1 << '\n';
}
mp2.clear();
return ;
}
mp[0] = ++tot;
v[1].push_back({0, 0});
mp2[0] = 0;
//if(sum >= 0) {
for(int i = 1; i <= n; ++ i) {
pre += a[i];
int now = pre % sum;
if(now < 0) now += abs(sum);//assert(now >= 0)!
if(!mp.count(now)) mp[now] = ++ tot;
if(mp2.count(pre)) continue;
int id = mp[now];
v[id].push_back({pre, i});
mp2[pre] = i;
}
for(auto it : mp) if(v[it.second].size()) sort(v[it.second].begin(), v[it.second].end());
for(int i = 1; i <= m; ++ i) {
int x; cin >> x;
int now = x % sum;
if(now < 0) now += abs(sum);
if(!mp.count(now)) {
cout << "-1\n";
}
else {
int id = mp[now];
int pos = lower_bound(v[id].begin(), v[id].end(), x) - v[id].begin();
if(sum >= 0) {
if(pos != v[id].size() && v[id][pos].x == x) cout << v[id][pos].y << '\n';
else if(pos == 0) cout << "-1\n";
else cout << v[id][pos - 1].y + (x - v[id][pos - 1].x) / abs(sum) * n << '\n';
}
else {
if(pos == v[id].size()) cout << "-1\n";
else cout << v[id][pos].y + (v[id][pos].x - x) / abs(sum) * n << '\n';
}
}
}
for(auto it : mp) v[it.second].clear();
//}
return ;
}
1010:构造题
很清晰就是如果任意一个点到其他点都有两条以上不同路径,那么图上必定有环并且所有点都在环上
然后可以发现给的边是互不连通的,那么必然有方法构造出2n条边环的情况。关键是字典序最小。
可以并查集贪心拿取,因为每个点只连两条边,所以连玩的点就扔掉,复杂度可以\(O(n)\)
#define int long long
const int maxn = 1e5 + 10, mod = 998244353;
struct node{
int x, y;
node(int x = 0, int y = 0) : x(x), y(y){}
bool operator < (const node &a) const {
if(x != a.x) return x < a.x;
else return y < a.y;
}
}a[maxn];
bool vis1[maxn], vis2[maxn];
int fa[maxn * 2];
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void un(int x, int y) {
if(find(x) != find(y))
fa[fa[x]] = fa[y];
}
void run() {
int n, m; cin >> n >> m;
for(int i = 1; i <= n; ++ i) vis1[i] = vis2[i] = 0;
for(int i = 1; i <= m; ++ i) cin >> a[i].x >> a[i].y, vis1[a[i].x] = 1, vis2[a[i].y] = 1;
cout << 2 * n - m << '\n';
vector<int> v1, v2;
for(int i = 1; i <= n; ++ i) {
if(!vis1[i]) v1.push_back(i);
if(!vis2[i]) v2.push_back(i);
}
vector<node> ans;
vector<int> sz(2 * n + 1);
//for(int i = 0; i < v1.size(); ++ i) a[++ m] = {v1[i], v2[i]}, ans.push_back({v1[i], v2[i]});
for(int i = 1; i <= n; ++ i) fa[i] = i, fa[i + n] = i + n;
for(int i = 1; i <= m; ++ i) un(a[i].x, a[i].y + n), sz[a[i].x] ++, sz[a[i].y + n] ++;
deque<int> q;
for(int i = 1; i <= n; ++ i) q.push_back(i);
for(int i = 1; i < n; ++ i) {
vector<int> tmp;
while(1) {
int top = q.front();
q.pop_front();
if(find(i) != find(top + n)) {
un(i, top + n), ans.push_back({i, top});
sz[i] ++; sz[top + n] ++;
}
if(sz[top + n] < 2) tmp.push_back(top);
if(sz[i] == 2) break;
}
for(int j = tmp.size() - 1; j >= 0; -- j) q.push_front(tmp[j]);
/*int top = q.front();
q.pop_front();
if(find(i) != find(top + n)) un(i, top + n), ans.push_back({i, top});
else {
int tpp = q.front();
q.pop_front();
q.push_front(top);
un(i, tpp + n), ans.push_back({i, tpp});
}*/
}
ans.push_back({n, q.front()}); q.pop_front();
if(q.size()) ans.push_back({n, q.front()});
sort(ans.begin(), ans.end());
for(auto it : ans) cout << it.x << ' ' << it.y << '\n';
return ;
}
1011:思维题
很巧妙的题目,真的感觉比前两题难度大,只能说太离谱
#define int long long
const int maxn = 1e5 + 10, mod = 998244353;
int fa[maxn], d[maxn];
int find(int x) {
if(x == fa[x]) return x;
int y = fa[x];
fa[x] = find(fa[x]);
d[x] += d[y];
return fa[x];
}
struct node{
int x, id;
node(int x = 0, int id = 0) : x(x), id(id){}
bool operator < (const node &a) const {
return x < a.x;
}
}a[maxn];
int un(int x, int y) {
find(x) != find(y);
d[fa[x]] = 1;
fa[fa[x]] = fa[y];
}
//按点权从小到大枚举结点 u,并将u作为所有与u 相连的(已经枚举过的)连通块的根。从而建立一棵新树,每个结点的深度(根的深度为 1)即是答案
vector<int> g[maxn];
int b[maxn];
void run() {
int n; cin >> n;
for(int i = 1, u, v; i < n; ++ i) {
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
for(int i = 1; i <= n; ++ i) {
cin >> b[i];
a[i] = {b[i], i};
fa[i] = i;
d[i] = 0;
}
sort(a + 1, a + 1 + n);
for(int i = 1; i <= n; ++ i)
for(auto it : g[a[i].id])
if(b[it] < a[i].x)
un(it, a[i].id);
for(int i = 1; i <= n; ++ i) {
find(i);
cout << d[i] + 1 << '\n';
g[i].clear();
}
return ;
}
``