Suggest some efficient algorithm in linear time - c++

You have an array A of length N consisting of positive integers. Let's consider N vertical segments (parallel to y axis) on the plane, the i-th segment connects the points (i, 0) and (i, Ai).
You have Q queries of following two types:
+ i X : Ai += X
? i L R: Let's consider R - L + 1 rays which are parallel to x axis. The j-th ray eminates at point (i - 0.5, L+ j - 1.5) and extends to the right infinitely long parallel to x axis. You have to print the number of the segments that will be shot by some ray. If a ray shoots a segment then it stops at that point and does't extend further.
Note that all the queries of the second type are independent of each other.
Code I tried produces right result but not much efficient:
int main()
{
int T;
int k;
cin>>T;
long int N,Q;
for(k=0;k<T;k++)
{
cin>>N>>Q;
vector<long int> v;
v.push_back(-1);
long int i=0,p;
for(i=0;i<N;i++)
{
cin>>p;
v.push_back(p);
}
for(long int j=0;j<Q;j++)
{
char c1;
cin>>c1;
if(c1=='+')
{
long int i;
int X;
cin>>i>>X;
v[i] = v[i] + X;
}
else
{
long int L,R,i;
cin>>i>>L>>R;
long int count=0,max=-100000;
for(long int l=i;l<=N;l++)
{
if(v[l]>=L && v[l]>max)
{
max=v[l];
count++;
if(max>=R)
break;
}
}
cout<<count<<endl;
}
}
}
}
T is here no of test cases.N is total no of elements in the array. Q is the no of queries on that array. So what I need is a better algorithm to do the same job that I did.

Related

Solving Wormholes (ZCO 2012)

Description:
The year is 2102 and today is the day of ZCO. This year there are N contests and the starting and ending times of each contest is known to you. You have to participate in exactly one of these contests. Different contests may overlap. The duration of different contests might be different.
There is only one examination centre. There is a wormhole V that transports you from your house to the examination centre and another wormhole W that transports you from the examination centre back to your house. Obviously, transportation through a wormhole does not take any time; it is instantaneous. But the wormholes can be used at only certain fixed times, and these are known to you.
So, you use a V wormhole to reach the exam centre, possibly wait for some time before the next contest begins, take part in the contest, possibly wait for some more time and then use a W wormhole to return back home. If you leave through a V wormhole at time t1 and come back through a W wormhole at time t2, then the total time you have spent is (t2 - t1 + 1). Your aim is to spend as little time as possible overall while ensuring that you take part in one of the contests.
You can reach the centre exactly at the starting time of the contest, if possible. And you can leave the examination centre the very second the contest ends, if possible. You can assume that you will always be able to attend at least one contest–that is, there will always be a contest such that there is a V wormhole before it and a W wormhole after it.
For instance, suppose there are 3 contests with (start,end) times (15,21), (5,10), and (7,25), respectively. Suppose the V wormhole is available at times 4, 14, 25, 2 and the W wormhole is available at times 13 and 21. In this case, you can leave by the V wormhole at time 14, take part in the contest from time 15 to 21, and then use the W wormhole at time 21 to get back home. Therefore the time you have spent is (21 - 14 + 1) = 8. You can check that you cannot do better than this.
Input:
The first line contains 3 space separated integers N, X, and Y, where N is the number of contests, X is the number of time instances when wormhole V can be used and Y is the number of time instances when wormhole W can be used. The next N lines describe each contest. Each of these N lines contains two space separated integers S and E, where S is the starting time of the particular contest and E is the ending time of that contest, with S < E. The next line contains X space separated integers which are the time instances when the wormhole V can be used. The next line contains Y space separated integers which are the time instances when the wormhole W can be used.
Output:
Print a single line that contains a single integer, the minimum time needed to be spent to take part in a contest.
My code:
#include <iostream>
#include <algorithm>
#include <vector>
#include <bits/stdc++.h>
#define loop(i,n) for(int i=0;i<n;++i)
#define FOR(i,a,b) for (int i = a; i < b; ++i)
#define ll long long
#define inf 9223372036854775807
#define printgrid(arr,m,n){cout<<"[";for(int i=0;i<m;++i){if(i!=0)cout<<" ";cout<<"[";for(int j=0;j<n;++j){cout<<arr[i][j];if(j!=n-1)cout<<" ";}cout<<"]";if(i!=m-1)cout<<endl;}cout<<"]"<<endl;}
using namespace std;
int searchl(int *arr,int s,int v)
{
int l=0;
int r=s-1;
while(l<=r)
{
int m = (l+r)/2;
if (arr[m] == v) return v;
if(arr[m]<v)
{
l = m + 1;
} else {
r = m - 1;
}
}
if (r<0) r=0;
return arr[r];
}
int searchh(int *arr,int s,int v)
{
int l=0;
int r=s-1;
while(l<=r)
{
int m = (l+r)/2;
if (arr[m] == v) return v;
if(arr[m]<v)
{
l = m + 1;
} else {
r = m - 1;
}
}
if(l>s-1) l=s-1;
return arr[l];
}
int main() {
int n,x,y;
cin>>n>>x>>y;
vector<pair<int,int>> v(n);
int a[x];
int b[y];
loop(i,n) cin >> v[i].first >> v[i].second;
loop(i,x) cin >> a[i];
loop(i,y) cin >> b[i];
sort(a,a+x);
sort(b,b+y);
int mn = 0x7fffffff;
int l;
int u;
loop(i,n)
{
l = searchl(a,x,v[i].first);
u = searchh(b,y,v[i].second);
mn = min(mn,(u-l+1));
}
cout << mn << endl;
}
What I tried is I use binary search for the lower range and upper range. and return the closest integer in the list. This should result in the lowest difference. This code AC's in 90% of the testcases however fails two testcases with a wrong answer.
Correct code:
#include <iostream>
#include <algorithm>
#include <vector>
#include <bits/stdc++.h>
#define loop(i,n) for(int i=0;i<n;++i)
#define FOR(i,a,b) for (int i = a; i < b; ++i)
#define ll long long
#define inf 9223372036854775807
#define printgrid(arr,m,n){cout<<"[";for(int i=0;i<m;++i){if(i!=0)cout<<" ";cout<<"[";for(int j=0;j<n;++j){cout<<arr[i][j];if(j!=n-1)cout<<" ";}cout<<"]";if(i!=m-1)cout<<endl;}cout<<"]"<<endl;}
using namespace std;
int searchl(int *arr,int s,int v)
{
int l=0;
int r=s-1;
while(l<=r)
{
int m = (l+r)/2;
if (arr[m] == v) return v;
if(arr[m]<v)
{
l = m + 1;
} else {
r = m - 1;
}
}
if (r<0) return -1;
return arr[r];
}
int searchh(int *arr,int s,int v)
{
int l=0;
int r=s-1;
while(l<=r)
{
int m = (l+r)/2;
if (arr[m] == v) return v;
if(arr[m]<v)
{
l = m + 1;
} else {
r = m - 1;
}
}
if(l>s-1) return -1;
return arr[l];
}
int main() {
cin.sync_with_stdio(false);
cin.tie(NULL);
int n,x,y;
cin>>n>>x>>y;
vector<pair<int,int>> v(n);
int a[x];
int b[y];
loop(i,n) cin >> v[i].first >> v[i].second;
loop(i,x) cin >> a[i];
loop(i,y) cin >> b[i];
sort(a,a+x);
sort(b,b+y);
int mn = 0x7fffffff;
int l;
int u;
loop(i,n)
{
l = searchl(a,x,v[i].first);
u = searchh(b,y,v[i].second);
if(u==-1 or l==-1) continue;
mn = min(mn,(u-l+1));
}
cout << mn << endl;
}

Using binary search to find k-th largest number in n*m multiplication table

So, I am trying to solve the problem: http://codeforces.com/contest/448/problem/D
Bizon the Champion isn't just charming, he also is very smart.
While some of us were learning the multiplication table, Bizon the Champion had fun in his own manner. Bizon the Champion painted an n × m multiplication table, where the element on the intersection of the i-th row and j-th column equals i·j (the rows and columns of the table are numbered starting from 1). Then he was asked: what number in the table is the k-th largest number? Bizon the Champion always answered correctly and immediately. Can you repeat his success?
Consider the given multiplication table. If you write out all n·m numbers from the table in the non-decreasing order, then the k-th number you write out is called the k-th largest number.
Input
The single line contains integers n, m and k (1 ≤ n, m ≤ 5·105; 1 ≤ k ≤ n·m).
Output
Print the k-th largest number in a n × m multiplication table.
What I did was, I applied binary search from 1 to n*m looking for the number which has exactly k elements less than it. For this, I made the following code:
using namespace std;
#define ll long long
#define pb push_back
#define mp make_pair
ll n,m;
int f (int val);
int min (int a, int b);
int main (void)
{
int k;
cin>>n>>m>>k;
int ind = k;
ll low = 1LL;
ll high = n*m;
int ans;
while (low <= high)
{
ll mid = low + (high-low)/2;
if (f(mid) == k)
ans = mid;
else if (f(mid) < k)
low = mid+1;
else
high = mid-1;
}
cout<<ans<<"\n";
return 0;
}
int f (int val)
{
int ret = 0;
for ( int i = 1; i <= n; i++ )
{
ret = ret + min(val/i,m);
}
return ret;
}
int min (int a, int b)
{
if (a < b)
return a;
else
return b;
}
However, I don't know why but this gives wrong answer on test cases:
input
2 2 2
output
2
My output comes out to be 0
I am learning binary search but I don't know where am I going wrong with this implementation. Any help will be appreciated.
Ignoring the fact that your binary search is not the fastest method, you still want to know why it is incorrect.
First be very clear about what you want and what your f is returning:
looking for the number which has exactly k elements less than it.
No! You are looking for the smallest number that has k elements less than or equal to it. And your function f(X) returns the count of elements less than or equal to X.
So when f(X) returns a value too small, you know X must be larger by at least 1, so low=mid+1 is correct. But when f(X) returns a value too large, X might be perfect (might be an element appearing several times in the table). Conversely, when f(X) returns exactly the right number, X might still be too big (X might be a value that appears zero times in the table).
So when f(X) is not too small, the best you can do is high=mid not high=mid-1
while (low < high)
{
ll mid = low + (high-low)/2;
if (f(mid) < k)
low = mid+1;
else
high = mid;
}
Notice low never gets > high, so stop when they are equal, and we don't try to catch the ans along the way. Instead at the end low==high==Answer
The contest says 1 second time limit. On my computer, your code with that correction solves the max size problem in under a second. But I'm not sure the judging computer is that fast.
Edit: int is too small for the max size of the problem, so you can't return int from f:
n, m, and i each fit in 32 bits, but the input and output of f() as well as k, ret, low and high all need to hold integers up to 2.5e11
import java.util.*;
public class op {
static int n,m;
static long k;
public static void main(String args[]){
Scanner s=new Scanner(System.in);
n=s.nextInt();
m=s.nextInt();
k=s.nextLong();
long start=1;
long end=n*m;
long ans=0;
while(end>=start){
long mid=start+end;
mid/=2;
long fmid=f(mid);
long gmid=g(mid);
if(fmid>=k && fmid-gmid<k){
ans=mid;
break;
}
else if(f(mid)>k){
end=mid-1;
}
else{
start=mid+1;
}
}
System.out.println(ans);
}
static long f (long val)
{
long ret = 0;
for ( int i = 1; i <= n; i++ )
{
ret = ret + Math.min(val/i,m);
}
return ret;
}
static long g (long val)
{
long ret = 0;
for ( int i = 1; i <= n; i++ )
{
if(val%i==0 && val/i<=m){
ret++;
}
}
return ret;
}
public static class Pair{
int x,y;
Pair(int a,int b){
x=a;y=b;
}
}
}

Isolating some vertices in a weighted tree with minimum cost

Suppose we are given a weighted tree and some set of vertices of that tree. The problem is to isolate those vertices(e.g. there should not be paths between them) by removing edges from the tree, such that the sum of the weights of removed edges is minimal.
I have been trying to solve this problem for about two hours, then I found solution in C++, but there was no explanation. As I understood it uses Dynamic Programming technique.
My question is what is the basic idea of solving this problem?
Thanks!
Here is the solution.
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
#define PB push_back
#define MP make_pair
typedef long long LL;
const int MAXN = 100005;
const LL inf = 1LL << 55;
int N, K;
bool bad[MAXN];
LL dp[MAXN][2];
vector<pair<int, int> > adj[MAXN];
void dfs(int u, int fa) {
dp[u][1] = 0;
dp[u][0] = bad[u] ? inf : 0;
for (int i = 0; i < adj[u].size(); i++) {
int v = adj[u][i].first, w = adj[u][i].second;
if (v != fa) {
dfs(v, u);
dp[u][1] += min(dp[v][0], dp[v][1] + w);
dp[u][1] = min(dp[u][1], dp[u][0] + dp[v][1]);
if (!bad[u])
dp[u][0] += min(dp[v][0], dp[v][1] + w);
}
}
}
int main() {
cin >> N >> K;
for (int i = 1; i < N; i++) {
int a, b, c;
cin >> a >> b >> c;
adj[a].PB(MP(b, c)); adj[b].PB(MP(a, c));
}
memset(bad, false, sizeof(bad));
for (int i = 0; i < K; i++) {
int x;
cin >> x;
bad[x] = true;
}
dfs(0, -1);
LL ret = min(dp[0][0], dp[0][1]);
cout << ret << endl;
return 0;
}
Formally, the problem is, given an acyclic undirected graph with weighted edges, together with a set of terminal vertices, find the minimum set of edges whose removal means that, for all pairs of distinct terminals, those terminals are no longer connected.
Root the graph arbitrarily and treat it as a general tree. We run a dynamic program that operates bottom-up on the vertices. Each vertex u has two labels: dp[u][0] is the minimum weight of edges to be removed in the subtree rooted at u so that no terminal in the subtree is connected to another terminal or to u, and dp[u][1] is the minimum removal weight that leaves exactly one subtree terminal connected to u. We have a recurrence
{ infinity if v is a terminal
dp[u][0] = { sum dp[v][0] otherwise
{ children v of u
dp[u][1] = min dp[v][1] + sum min(dp[w][0], dp[w][1] + weight(uw)),
children v of u other children w of v
taking an empty min to be infinity.

Find Middle points(Computational geometry c++)

This program should read for input an integer N then the x and y coordinates of the N points
and return the number of points that are the middle points of any two other points in the set.
First the program stores the points in an array then we loop throgh the points and calculate the distance between points[i] and every other point. We sort the points according to that distance then if we find that any two points have the same distance we check if point[i] is aligned with them if it is the case we store point[i] in the middles list.
We then get rid of doubles in the list and return the size of the list.
I submitted my solution and it doesn't work for all the cases. Please help:
#include <iostream>
#include <cmath>
#include <algorithm>
#include <list>
#include <stdio.h>
using namespace std;
struct Point
{
int x;
int y;
int distance;
};
bool PointSort(Point a,Point b);
bool colinear(Point a,Point b,Point c);
bool same_point (Point first, Point second);
int main()
{
list<Point> middles;
int N;scanf("%d", &N);
Point points[N];
Point points2[N];
for(int i=0;i<N;i++)
{ scanf("%d", &points[i].x);
scanf("%d", &points[i].y);
points2[i].x=points[i].x;
points2[i].y=points[i].y;
}
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
points2[j]=points[j];
}
for(int j=0;j<N;j++)
{
points2[j].distance=(points[i].x-points2[j].x)*(points[i].x- points2[j].x)+(points[i].y-points2[j].y)*(points[i].y-points2[j].y);
}
sort(points2,points2+N,&PointSort);
for(int j=0;j<N;j++)
{
int k=j+1;
while(points2[j].distance==points2[k].distance)
{
bool coli=colinear(points[i],points2[j],points2[k]);
if(coli){middles.push_back(points2[i]);}
k++;
}
}
}
middles.unique(same_point);
cout<<middles.size();
}
bool PointSort(Point a,Point b)
{
return a.distance<b.distance;
}
bool colinear(Point a,Point b,Point c)
{
return (a.x*(b.y-c.y)+b.x*(c.y-a.y)+c.x*(a.y-b.y))/2.0==0.0;
}
bool same_point (Point first, Point second)
{ return (first.x==second.x && first.y==second.y) ; }
You actually don't need to calculate distances to check if something is the midpoint. The coordinates of the midpoint between A and B is M=(A+B)/2. Or, to keep everything as an integer, A+B=2M where M is the midpoint. Here's a pseudocode solution for the problem:
for ( A=0; A<N-1; A++ ) {
for ( B=A+1; B<N; B++ ) {
M2 = A+B;
for ( C=0; C<N; C++ ) {
if ( C*2 == M2 ) {
// C is the midpoint of A and B
}
}
}
}
I see the following potential problems with your code:
Your code computes the distance squared (not the distance as stated) between pairs of points. Since the calculation is being done using integer arithmetic, there's a chance of arithmetic overflow.
Your code removes all midpoints found with duplicated x and y coordinates. But, is this what the problem statement requires? If duplicate points actually appear in the input stream, and happen to be midpoints of some other points, should the second and all subsequent duplicates be ignored? Also, if a point is duplicated three (or more) times in the input stream, how many midpoints does that count as? You should carefully check the problem statement to see how duplicates in the input stream should be counted and follow the requirements precisely.
Your check for collinearity looks wrong. You appear to be trying to take a 2d cross of (points[i] - points2[j]) with (points[i] - points2[k]), but this is not the correct way to do it. Here is how to take a 2d cross:
int cross2d(Point a, Point mid, Point c)
{
// Take the 2d cross product (a - mid) X (c - mid).
// 2d cross = (u.x * v.y - u.y * v.x) where u = (a-mid) and v=(c - mid)
int cross = (a.x - mid.x) * (c.y - mid.y) - (a.y - mid.y) * (c.x - mid.x);
return cross;
}
bool collinear(Point a, Point mid, Point c)
{
// Check for the points being collinear (or degenerate, i.e. return true if a == mid or mid == c).
return cross2d(a, mid, c) == 0;
}
Again, integer overflow is a potential problem for point triplets with large coordinates that are nearly perpendicular. And if you were not trying to take a 2d cross, what were you trying to do?
You're trying create an O(n-squared) algorithm by sorting the points by distance from some prospective midpoint. That's creditable, but since your code isn't working I would start by creating a naive O(n-cubed) algorithm that solves the problem straightforwardly. Then you can use that to unit-test your improved n-squared algorithm.
Adding some spacing into your mathematical expressions makes them easier to read.
So, to start you off, here's the naive n-cubed algorithm. Note that I am preserving duplicates in the input stream while avoiding double-counting of points that are midpoints of multiple pairs of points:
#include <iostream>
#include <cmath>
#include <algorithm>
#include <list>
#include <stdio.h>
using namespace std;
struct Point
{
int x;
int y;
int id;
};
bool is_middle(Point a, Point middle, Point c);
bool same_point_id(Point first, Point second);
int main()
{
list<Point> middles;
int N;
scanf("%d", &N);
// https://stackoverflow.com/questions/25437597/find-middle-pointscomputational-geometry-c
// This program should read for input an integer N then the x and y coordinates of the N points
// and return the number of points that are the middle points of any two other points in the set.
Point *points = new Point[N];
for(int i=0;i<N;i++)
{
scanf("%d", &points[i].x);
scanf("%d", &points[i].y);
points[i].id = i;
}
for(int i=0; i<N-2; i++)
{
for(int j=i+1; j<N-1; j++)
{
for(int k=j+1; k<N; k++)
{
// Check the problem requirement to determine how to count sets of three identical points in the input stream.
if (is_middle(points[i], points[j], points[k]))
middles.push_back(points[j]);
if (is_middle(points[j], points[k], points[i]))
middles.push_back(points[k]);
if (is_middle(points[k], points[i], points[j]))
middles.push_back(points[i]);
}
}
}
// Prevent the same input point from being counted multiple times.
middles.unique(same_point_id);
cout<<middles.size();
delete [] points;
}
bool is_middle(Point a, Point mid, Point c)
{
if (a.x - c.x != 2*(a.x - mid.x))
return false;
if (a.y - c.y != 2*(a.y - mid.y))
return false;
return true;
}
bool same_point_id(Point first, Point second)
{
return (first.id==second.id);
}
Update: If you do need an n-squared algorithm then sorting potential endpoints by distance squared from the midpoint isn't a bad idea. If you want to avoid potential arithmetic overflows, you can do calculate the distance squared in 64bit long long ints:
long long distance_squared(Point a, Point b)
{
long long dx = ((long long)a.x - (long long)b.x);
long long dy = ((long long)a.y - (long long)b.y);
return dx*dx + dy*dy;
}
On most platforms these will have more bits than a regular int -- and certainly not fewer.

Combination with repetition, differences in calculation

I have a small program. I have to calculate combination with repetition.
My code:
int factorial(int a){
if (a<0)
return 0;
if (a==0 || a==1)
return 1;
return factorial(a-1)*a;
}
long int combinationWithRepetion(int n, int k){
long int a,b,wyn=0;
wyn=factorial(n+(k-1))/(factorial(k)*factorial(n-1));
return wyn;
}
int main()
{
int k,n=0;
cout<<"Give n: ";
cin>>n;
cout<<"Give k: ";
cin>>k;
cout<<"combination With Repetion for n="<<n<<
" k="<<k<<".\n Is equal to "<<combinationWithRepetion(n,k)<<endl;
return 0;
}
For n=9 and k=6 in Wolfram alfa I get 3003, but in this program the result is 44.
For me the code is fine.
With n=9 and k=6 you compute factorial(14) which is 87,178,291,200 which will overflow a 4-byte int. You need to use something like long long to get an 8-byte int if you want to use this formula.
There are better formulas for computing binomial coefficients which do not rely on computing the full factorials then doing the division. See Binomial coefficient in programming languages, the direct method (rather than using recursion).
In C++ you can use:
int binomial(int N, int K) {
if( K > N - K )
K = N - K;
int c = 1;
for(int i = 0; i < K; ++i) {
c *= (N - i);
c /= (i + 1);
}
return c;
}
So you are calculating (n+k-1) choose k. Substiuting n=9,k=6, it is 14choose6(=3003). But 14! takes more than 36bits to represent, but your int only has 32 bits. A better implementation would be to simplify n!/((n-k)!k!) to n(n-1)...(n-k+1)/k!. Or you can use pascal triangle.