Challenge: Count Triangles
Scor cont: 140.0 / 200
Submission status: Terminated due to timeout
Submission score: 0.7
Submission ID: 464904921
Limbaj: cpp14
Link challenge: https://www.hackerrank.com/challenges/count-triangles/problem
Cerinta
You are given a regular N-gon with vertices at (cos(2πi / N), sin(2πi / N)), ∀ i ∈ [0,N-1]. Some of these vertices are blocked and all others are unblocked. We consider triangles with vertices at the vertices of N-gon and with at least one vertex at unblocked point. Can you find how many *pairs* of such triangles have equal area?
**Input Format**
The first line of input contains single integer T - number of testcases. 2T lines follow.
Each testcase has two lines.
The first line of testcase contains a single integer N - the number of vertices in N-gon. The second line contains string S with length N. If S[j] equals '1' it means that the vertex (cos(2πj / N), sin(2πj / N)) is unblocked, and if S[j] equals '0' it means that the vertex (cos(2πj / N), sin(2πj / N)) is blocked.
**Output Format**
For each testcase output single line with an answer.
**Constraints**
1 <= T <= 100
3 <= N <= 10<sup>4</sup>
There will be no more than 50 blocked vertices in each of the testcase.
**Sample Input**
1
4
1111
**Sample Output**
6
**Explanation**
The testcase given is a square and there are 4 triangles that have the same area. So, the number of pairs are 4C2 = 6.
Cod sursa
#include <bits/stdc++.h>
using namespace std;
using u64 = uint64_t;
using u32 = uint32_t;
using i64 = long long;
using u128 = unsigned __int128;
using i128 = __int128;
u64 mpow(u64 a,u64 e,u64 m){u64 r=1;a%=m;while(e){if(e&1)r=(u128)r*a%m;a=(u128)a*a%m;e>>=1;}return r;}
bool isp(u64 n){
if(n<2)return 0;if(n<4)return 1;if(n%2==0||n%3==0)return 0;
u64 d=n-1;int s=0;while(!(d&1)){d>>=1;s++;}
for(u64 a:{2,3,5,7,11,13,17,19,23,29,31,37}){
if(a>=n)continue;u64 x=mpow(a,d,n);if(x==1||x==n-1)continue;
bool c=1;for(int r=1;r<s;r++){x=(u128)x*x%n;if(x==n-1){c=0;break;}}
if(c)return 0;
}return 1;
}
u64 findp(u64 m,u64 lo){u64 k=(lo+m-1)/m;while(!isp(k*m+1))k++;return k*m+1;}
u64 proot(u64 p){
u64 phi=p-1,n=phi;vector<u64>fs;
for(u64 i=2;i*i<=n;i++){if(n%i==0){fs.push_back(i);while(n%i==0)n/=i;}}
if(n>1)fs.push_back(n);
for(u64 g=2;;g++){bool ok=1;for(u64 f:fs)if(mpow(g,phi/f,p)==1){ok=0;break;}if(ok)return g;}
}
static const int MAX_TRI = 8'400'000;
static u32 K[MAX_TRI], K2[MAX_TRI]; // primary key h1
static u32 P[MAX_TRI], P2[MAX_TRI]; // payload: (h2<<2)|mtype
static u64 S1[10001], S2[10001];
static u64 V1[10001], V2[10001];
struct TestBad {
vector<pair<u64,int>> bad; // (combined key, bad count)
};
static inline void radix_sort_u32_pair(u32* k, u32* p, u32* kbuf, u32* pbuf, int n){
static int cnt[65536];
memset(cnt,0,sizeof(cnt));
for(int i=0;i<n;i++) cnt[k[i] & 0xFFFF]++;
int sum=0;
for(int i=0;i<65536;i++){int c=cnt[i]; cnt[i]=sum; sum+=c;}
for(int i=0;i<n;i++){
int b = k[i] & 0xFFFF;
int pos = cnt[b]++;
kbuf[pos]=k[i]; pbuf[pos]=p[i];
}
memset(cnt,0,sizeof(cnt));
for(int i=0;i<n;i++) cnt[kbuf[i] >> 16]++;
sum=0;
for(int i=0;i<65536;i++){int c=cnt[i]; cnt[i]=sum; sum+=c;}
for(int i=0;i<n;i++){
int b = kbuf[i] >> 16;
int pos = cnt[b]++;
k[pos]=kbuf[i]; p[pos]=pbuf[i];
}
}
static inline void print128(i128 x){
if(x==0){ putchar('0'); return; }
if(x<0){ putchar('-'); x=-x; }
char buf[50]; int n=0;
while(x>0){ buf[n++] = char('0' + (int)(x%10)); x/=10; }
while(n--) putchar(buf[n]);
}
int main(){
int T; if(scanf("%d",&T)!=1) return 0;
struct TC{ int N; char S[10001]; };
vector<TC> tc(T);
for(int i=0;i<T;i++) if(scanf("%d%s",&tc[i].N,tc[i].S)!=2) return 0;
map<int, vector<int>> byN;
for(int i=0;i<T;i++) byN[tc[i].N].push_back(i);
vector<i128> ans(T);
for(auto &itN : byN){
int N = itN.first;
auto &ids = itN.second;
u64 m = 2ULL * N;
u64 p1 = findp(m, 500000000ULL);
u64 p2 = findp(m, p1 + m);
auto buildS = [&](u64 p, u64* S){
u64 g=proot(p), w=mpow(g,(p-1)/m,p), wi=mpow(w,p-2,p);
u64 wp=1, wn=1;
for(int k=0;k<=N;k++){
S[k]=(wp + p - wn) % p;
if(k<N){ wp=(u128)wp*w%p; wn=(u128)wn*wi%p; }
}
};
buildS(p1,S1);
buildS(p2,S2);
for(int k=1;k<N;k++){
int dk=2*k;
V1[k] = (dk<=N)? S1[dk] : (p1 - S1[dk-N]) % p1;
V2[k] = (dk<=N)? S2[dk] : (p2 - S2[dk-N]) % p2;
}
vector<TestBad> badByTest(ids.size());
unordered_map<u64, i64> needFull; // key -> full count (filled later), init -1
needFull.reserve((size_t)ids.size()*1000 + 1024);
// precompute blocked key counts per test and union key set
for(size_t ti=0; ti<ids.size(); ++ti){
int idx = ids[ti];
char* S = tc[idx].S;
int blk[51], B=0;
for(int i=0;i<N;i++) if(S[i]=='0') blk[B++]=i;
if(B<3) continue;
vector<u64> tmp; tmp.reserve((size_t)B*(B-1)*(B-2)/6);
for(int i=0;i<B;i++) for(int j=i+1;j<B;j++){
int g1 = blk[j]-blk[i];
for(int k=j+1;k<B;k++){
int g2=blk[k]-blk[j], g3=N-blk[k]+blk[i];
int a=g1,b=g2,c=g3;
if(a>b) swap(a,b); if(b>c) swap(b,c); if(a>b) swap(a,b);
u64 h1 = V1[a] + V1[b]; if(h1>=p1) h1-=p1; h1 += V1[c]; if(h1>=p1) h1-=p1;
u64 h2 = V2[a] + V2[b]; if(h2>=p2) h2-=p2; h2 += V2[c]; if(h2>=p2) h2-=p2;
u64 key = (h1<<30) | h2;
tmp.push_back(key);
}
}
sort(tmp.begin(), tmp.end());
vector<pair<u64,int>> comp;
for(size_t i=0;i<tmp.size();){
size_t j=i+1; while(j<tmp.size() && tmp[j]==tmp[i]) ++j;
comp.push_back({tmp[i], (int)(j-i)});
if(!needFull.count(tmp[i])) needFull.emplace(tmp[i], -1);
i=j;
}
badByTest[ti].bad.swap(comp);
}
vector<u32> needPrimary;
needPrimary.reserve(needFull.size());
for(auto &kv: needFull){ needPrimary.push_back((u32)(kv.first >> 30)); }
sort(needPrimary.begin(), needPrimary.end());
needPrimary.erase(unique(needPrimary.begin(), needPrimary.end()), needPrimary.end());
// generate partitions
int nt=0;
for(int a=1;a<=N/3;a++){
u64 va1=V1[a], va2=V2[a];
int bmax=(N-a)/2;
for(int b=a;b<=bmax;b++){
int c=N-a-b;
int mtype = (a==b && b==c)?0:((a==b || b==c)?1:2);
u64 h1=va1+V1[b]; if(h1>=p1) h1-=p1; h1 += V1[c]; if(h1>=p1) h1-=p1;
u64 h2=va2+V2[b]; if(h2>=p2) h2-=p2; h2 += V2[c]; if(h2>=p2) h2-=p2;
K[nt]=(u32)h1;
P[nt]=(u32)((h2<<2) | (u32)mtype);
++nt;
}
}
radix_sort_u32_pair(K,P,K2,P2,nt);
const i64 mult[3] = {N/3, N, 2LL*N};
i128 bp=0;
size_t qptr=0;
auto needThisPrimary = [&](u32 pri)->bool{
while(qptr < needPrimary.size() && needPrimary[qptr] < pri) ++qptr;
return qptr < needPrimary.size() && needPrimary[qptr] == pri;
};
// scan by primary runs; exact group by secondary inside run
for(int i=0;i<nt;){
u32 pri = K[i];
int j=i+1; while(j<nt && K[j]==pri) ++j;
bool needPri = needThisPrimary(pri);
if(j==i+1){
u32 sec = P[i]>>2;
i64 total = mult[P[i]&3U];
bp += (i128)total*(total-1)/2;
if(needPri){
u64 key = ((u64)pri<<30) | sec;
auto it = needFull.find(key);
if(it != needFull.end()) it->second = total;
}
} else {
// local grouping by secondary (run is usually tiny)
static u32 secs[256];
static i64 sums[256];
int cnt=0;
bool fallback=false;
for(int t=i;t<j;t++){
u32 sec = P[t]>>2;
i64 val = mult[P[t]&3U];
int pos=-1;
for(int z=0; z<cnt; z++){ if(secs[z]==sec){ pos=z; break; } }
if(pos==-1){
if(cnt<256){ secs[cnt]=sec; sums[cnt]=val; cnt++; }
else { fallback=true; break; }
} else sums[pos]+=val;
}
if(!fallback){
for(int z=0; z<cnt; z++){
i64 total=sums[z];
bp += (i128)total*(total-1)/2;
if(needPri){
u64 key=((u64)pri<<30)|secs[z];
auto it=needFull.find(key);
if(it!=needFull.end()) it->second=total;
}
}
} else {
// very rare fallback
unordered_map<u32,i64> mp;
mp.reserve((j-i)*2);
for(int t=i;t<j;t++) mp[P[t]>>2] += mult[P[t]&3U];
for(auto &kv: mp){
i64 total=kv.second;
bp += (i128)total*(total-1)/2;
if(needPri){
u64 key=((u64)pri<<30)|kv.first;
auto it=needFull.find(key);
if(it!=needFull.end()) it->second=total;
}
}
}
}
i=j;
}
// answer per test
for(size_t ti=0; ti<ids.size(); ++ti){
i128 res=bp;
for(auto &bk: badByTest[ti].bad){
u64 k=bk.first; i64 bad=bk.second;
auto itf = needFull.find(k);
i64 full = (itf==needFull.end() || itf->second<0) ? 0 : itf->second;
res -= (i128)bad*(full-bad) + (i128)bad*(bad-1)/2;
}
ans[ids[ti]] = res;
}
}
for(int i=0;i<T;i++){ print128(ans[i]); putchar('\n'); }
return 0;
}
HackerRank Geometry – Count Triangles
