ْ
# | User | Rating |
---|---|---|
1 | jiangly | 3976 |
2 | tourist | 3815 |
3 | jqdai0815 | 3682 |
4 | ksun48 | 3614 |
5 | orzdevinwang | 3526 |
6 | ecnerwala | 3514 |
7 | Benq | 3482 |
8 | hos.lyric | 3382 |
9 | gamegame | 3374 |
10 | heuristica | 3357 |
# | User | Contrib. |
---|---|---|
1 | cry | 169 |
2 | -is-this-fft- | 165 |
3 | Um_nik | 161 |
3 | atcoder_official | 161 |
5 | djm03178 | 157 |
6 | Dominater069 | 156 |
7 | adamant | 154 |
8 | luogu_official | 152 |
9 | awoo | 151 |
10 | TheScrasse | 147 |
Hello Codeforces. This year I participated in IOI, and I did really bad. I want to improve throughout the year and try to manage my time with studying for school since this is graduation year. I want to find optimal way to practice, since I'm feeling that Codeforces problems are not really IOI-like. I was thinking of solving OI problems, but I don't really know how to sort them so that I can find problems for my level, since oj sorting style isn't really useful. Also I'm not even sure if simply solving problems throughout the year is useful alone too. Enough of my chaotic thoughts, I want to ask people who did well in IOI, at least silver, how do you practice? What sites do you usually solve on? How do you decide where to solve problem? You get the idea. I tried searching for blogs about these stuff but I only found the one by E869120 but it only talks about his strategy and speedsolving practice, which is useful, but definitely not everthing. I appreciate any replies.
Many graph problems have subtasks where the graph is a complete binary tree (edge between i and i*2, i and i*2+1), however I often struggle with them. Does anyone know a useful resource that discusses different techniques to approach such a problem/subtask?
Hello! IIOT is an olympiad for teams of 4. It's going to be in Syria this year on May 10th. My team will be there onsite (unofficial participation though):
Abito — De3b0o — Ryuk_999 — Lemoliz
Other Syrian teams:
Ahmad_OS — Abdalaziz_Alshami — Karam_Kallasi — K.Al-Ani7 Unofficial
Haidora + 3 Unofficial
NeroZein — hocln — 3laa — M_sawas_ Official
edogawa_something — aminsh — YazanAlattar — Bash. Official
If you know other participating teams please share!
Sometimes I encounter a type of range queries that I don't know how to do using segment tree, so I use a merge sort tree instead. It can answer queries in $$$O(log^2 n ) $$$. I decided to share this because it can be useful to many in contests. First, we know that a node in a segment tree stores the answer for a range of length $$$2^x$$$ for some $$$x$$$, but we can also store in it all the elements in the range sorted in a vector (using merge sort algo) or set or whatever. Here I am going to give a few examples how we can use this to our advantage.
We are given an array $$$a_1, a_2, a_3... a_n$$$ and an integer $$$q$$$. The $$$i$$$_th of the next $$$q$$$ lines has three integers $$$l_i , r_i , x_i$$$. The answer for this query is how many $$$a_j$$$ such that $$$l_i \le j \le r_i$$$ and $$$a_j < x$$$.
Let's create a merge sort tree where each node has a sorted vector containing all elements in the range of this node. Now we can answer the query recursively like a segment tree. For some $$$node$$$ if $$$[l_{node},r_{node}]$$$ is outside $$$[l_i,r_i]$$$ its answer is obviously $$$0$$$. If its entirely contained, we can do binary search on the vector to find how many elements satisfy the conditions. If neither of the previous conditions are satisfied, we take the answer of the right child + the answer of the left child. Time complexity for building the merge sort tree is $$$O(nlogn)$$$ because we go through each element $$$logn$$$ times, and the time complexity for answering the queries is $$$O(qlog^2n)$$$ because in each query we visit logn nodes at most, doing binary search in each one in $$$O(logn)$$$.
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,q,a[N];
vector<int> seg[4*N+5];
//build merge sort tree
void build(int node,int l,int r){
//if range length is 1 there's only one element to add and no children
if (l==r){
seg[node].push_back(a[l]);
return;
}int mid=(l+r)/2;
build(node*2,l,mid);
build(node*2+1,mid+1,r);
int i=0,j=0;
// use two pointers to merge the two vectors in O(r-l+1)
while (i<seg[node*2].size() && j<seg[node*2+1].size()){
if (seg[node*2][i]<seg[node*2+1][j]) seg[node].push_back(seg[node*2][i++]);
else seg[node].push_back(seg[node*2+1][j++]);
}
while (i<seg[node*2].size()) seg[node].push_back(seg[node*2][i++]);
while (j<seg[node*2+1].size()) seg[node].push_back(seg[node*2+1][j++]);
return;
}
//query
int query(int node,int l,int r,int lx,int rx,int x){
//if outside -> 0
if (l>rx || r<lx) return 0;
//if inside do binary search
if (l>=lx && r<=rx){
int L=0,R=seg[node].size()-1,mid,ans=0;
while (L<=R){
mid=(L+R)/2;
if (seg[node][mid]<x){
ans=mid+1;
L=mid+1;
}else R=mid-1;
}return ans;
}
int mid=(l+r)/2;
return query(node*2,l,mid,lx,rx,x)+query(node*2+1,mid+1,r,lx,rx,x);
}
int32 main(){
cin>>n>>q;
for (int i=1;i<=n;i++) cin>>a[i];
build(1,1,n);
while (q--){
int l,r,x;
cin>>l>>r>>x;
cout<<query(1,1,n,l,r,x)<<endl;
}
return 0;
}
We are given an array $$$a_1, a_2, a_3... a_n$$$ and an integer $$$q$$$. The $$$i$$$_th of the next $$$q$$$ lines has an integer $$$t_i$$$, describing the type of query.
Let's create something similar to merge sort tree, where each node has a multiset of the elements in its range, we can loop through these values. Building time complexity is $$$O(nlog^2 n)$$$ because we add each element $$$logn$$$ times with time complexity $$$O(logn)$$$ because multiset. Now to the queries. When we are supposed to change some element, we go through the segment tree and remove it from each node that contains it and add its new value instead. This is also in $$$O(log^2 n )$$$ because we add to $$$logn$$$ nodes at most, each with time complexity $$$O(logn)$$$ because multiset. Now for the other type of queries, we do similar to the previous problem. If a node is outside the query range we return $$$INF$$$. If a node is entirely inside the query range we return the lower bound in this node's multiset. Else we want the minimum of the answer of the node's right child and left child answers. Time complexity of this queries is $$$O(log^2n)$$$ because we go through $$$logn$$$ nodes at worst case each with time complexity $$$O(logn)$$$ because of binary search (lower bound function). Time compleixty overall: $$$O((q+n)log^2n)$$$.
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,q,a[N];
multiset<int> seg[4*N+5];
void build(int node,int l,int r){
if (l==r){
seg[node].insert(a[l]);
return;
}int mid=(l+r)/2;
build(node*2,l,mid);
build(node*2+1,mid+1,r);
for (int i=l;i<=r;i++) seg[node].insert(a[i]);
return;
}
void edit(int node,int l,int r,int idx,int val){
if (l==r){
seg[node].erase(a[idx]);
seg[node].insert(val);
return;
}int mid=(l+r)/2;
if (idx<=mid) edit(node*2,l,mid,idx,val);
else edit(node*2+1,mid+1,r,idx,val);
seg[node].erase(a[idx]);
seg[node].insert(val);
return;
}
int query(int node,int l,int r,int lx,int rx,int x){
if (l>rx || r<lx) return INT_MAX;
if (l>=lx && r<=rx){
auto it=seg[node].lower_bound(x);
if (it==seg[node].end()) return INT_MAX;
return *it;
}int mid=(l+r)/2;
return min(query(node*2,l,mid,lx,rx,x),query(node*2+1,mid+1,r,lx,rx,x));
}
int32_t main(){
ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
cin>>n>>q;
for (int i=1;i<=n;i++) cin>>a[i];
build(1,1,n);
while (q--){
bool t;cin>>t;
if (!t){
int idx,val;
cin>>idx>>val;
edit(1,1,n,idx,val);
a[idx]=val;
continue;
}int l,r,x;cin>>l>>r>>x;
int y=query(1,1,n,l,r,x);
if (y==INT_MAX) cout<<-1<<endl;
else cout<<y<<endl;
}
return 0;
}
There are many other things that you can do using technique. You can even solve the dynamic version of the first problem using indexed_set. However you should use this only when you're desperate because it's really slow. Yes it's $$$O(nlog^2n)$$$ but the constant factor is very high because it's segment tree + sets. If you have intereseting problems to add to the blog, or you notice some mistake please say in the comments. Good luck everyone!
Next contest should be 879. Please fix. Edit: fixed.
Troll accounts are nearly unescapable. No matter what restrictions are made, there will always be troll accounts, but please at least decrease spam. Look at recent actions now, it's all the same account. I think that having a time limit between blogs, like you can post another blog only 1 hour after another is good. What do you people think?
Don't use sqrt because precision issues
Also here is implementation to find floor(sqrt(x))
#define int long long
int sqrt(int x){
int l=1,r=1e9+5,ans=0,mid;
while (l<=r){
mid=(l+r)/2;
if (mid*mid<=x){
ans=mid;
l=mid+1;
}else r=mid-1;
}return ans;
}
It seems std::sqrt works fine in C++17 though. Also sqrtl seems to give correct results
Hello Codeforces! So my friend Haidora thought that in problem C yesterday it asked for the number of beautiful sets of all lengths (lol) and we were talking now about a solution for this problem and came up with an $$$O(rlogr)$$$ DP solution.
A set of positive integers $$$S$$$ is called beautiful if, for every two integers $$$x$$$ and $$$y$$$ from this set, either $$$x$$$ divides $$$y$$$ or $$$y$$$ divides $$$x$$$ (or both).
You are given two integers $$$l$$$ and $$$r$$$ . Consider all beautiful sets consisting of integers not less than $$$l$$$ and not greater than $$$r$$$: You have to print their number modulo $$$998244353$$$
Let $$$dp_x$$$ be the number of beautiful sets we can build such that the minimum number in these sets is $$$x$$$. Now, how do we find $$$dp_x$$$? Let's iterate through all numbers $$$i$$$ such that $$$xi \le r$$$, which means that we'll go through all multiples of $$$x$$$ as long as they are less than $$$r$$$. Now let's add their answers to our $$$dp_x$$$. Formally:
$$$dp_x = 1 + \sum_{i=2}^{xi \le r} dp_{xi} $$$ Now our answer would be summing them all up, because we want all sets, so for all possible minimums we want to know the number of sets possible using it. Formally: $$$ans = \sum_{i=l}^{i \le r} dp_{i} $$$
Note that the $$$1+$$$ is there because choosing $$$x$$$ alone in a set is also valid.
Why is it $$$O(rlogr)$$$? For each $$$x$$$ you are iterating through all number $$$xi \le r$$$ which is $$$r \sum_{i=l}^{i \le r} dp_{1/i} $$$ which is close to $$$O(rlogr)$$$ Thanks to NaimSS for correcting my time complexity.
I used recursive DP:
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+5,M=998244353;
int dp[N],l,r;
int rec(int x){
if (x>r) return 0;
if (dp[x]) return dp[x];
dp[x]=1;
for (int i=2;i*x<=r;i++) dp[x]=(dp[x]+rec(x*i))%M;
return dp[x];
}
int main(){
ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
cin>>l>>r;
int ans=0;
for (int i=l;i<=r;i++) ans=(ans+rec(i))%M;
cout<<ans<<endl;
return 0;
}
This code runs less than 100ms on C++20(64) when $$$l = 1$$$ and $$$r = 10^6$$$ , and less than 2000ms when $$$l = 1$$$ and $$$r = 10^7$$$. Tried on Codeforces custom test.
Iterative DP by Farsh_LE:
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+5,M=998244353;
int dp[N],l,r;
int main(){
ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
cin>>l>>r;
int ans=0;
for (int x=r;x>=l;x--){
dp[x]=1;
for (int i=2;x*i<=r;i++) dp[x]=(dp[x]+dp[x*i])%M;
ans=(ans+dp[x])%M;
}cout<<ans<<endl;
return 0;
}
Nearly same speed as recursive, a bit faster though.
This is my first blog of this kind, so feel free to share your opinions as it will help me and others for the future. Also, please point out any mistakes you find. And I have a few questions: Could there be a faster solution? Also if there is an iterative DP solution please share it, because I couldn't find any way to do it iteratively. Thanks!
Last year a contest was held on Valentine's Day. Why isn't is the same this year? Do you expect us to go on dates? Please give us Valentine's Day contest :(
Many people use the normal upper_bound()
function, which is slow (at worst case O(n)) and get TLE. When you are using a set/multiset/map, use containername.upper_bound()
This function uses Binary Search which runs at O(logn) time. Please be careful next time. This is only a reminder because I'm seeing a lot of people get TLE because of this.
Hello Codeforces. I'm trying to add my wallet in magic place but it's asking for a secret code and I don't know how to find it. I'm using tonkeeper app. If anyone knows how to find it please help me. Thanks in advance!
Hello everyone. So Global Rounds are made every 2 months and last one was in June, but as I can see there isn't going to be a Global Round this month. Why is that? Is it postponed to September or something?
Name |
---|