TEAMNAME - Editorial

2 Likes

I did an O(n^2) solution with string hashing, it didn’t work for one task (TLE) . Can somebody please help, TIA.

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>

using namespace std;
using namespace __gnu_pbds;

#define vi vector<int>
#define vll vector<ll>
#define vvi vector < vi >
#define pb(x) push_back(x)
#define pii pair<int,int>
#define pll pair<long long, long long>
#define all(c) c.begin(),c.end()
#define mp(x,y) make_pair(x,y)
#define mem(a,val) memset(a,val,sizeof(a))
#define eb emplace_back
#define ff first
#define ss second
#define lc(p) (p << 1)
#define rc(p) (p << 1) | 1
#define ps(x, y) fixed << setprecision(y) << x
#define mk(arr, n, type) type *arr = new type[n]
#define range(a, b) substr(a, b - a + 1)
#define trace(x) cerr << #x << ": " << x << endl
#define FIO ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define input(arr,n) FOR(i,0,n) cin>>a[i]
#define FOR(i,k,n) for ( int i=k; i<n; i++ )
#define ROF(i,k,n) for ( int i=k; i>n; i-- )
#define ll long long

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int N = 20;
const int mod = 1e9 + 7;
const int base = 33;
 
int add(int a, int b, int mod){
    int res = (a + b) % mod;
    if(res < 0)
        res += mod;
    return res;
}
 
int mult(int a, int b, int mod){
    int res = (a * 1LL * b) % mod;
    if(res < 0)
        res += mod;
    return res;
}
 
int power(int a, int b, int mod){
    int res = 1;
    while(b){
        if((b % 2) == 1)
            res = mult(res, a, mod);
        a = mult(a, a, mod);
        b /= 2;
    }
    return res;
}
 
int pw[N];
int inv[N];
 
void precalc() {
    pw[0] = 1;
    for(int i = 1; i < N; i++)
        pw[i] = mult(pw[i - 1], base, mod);
    
    int pw_inv = power(base , mod - 2 , mod);
    inv[0] = 1;
    for(int i = 1; i < N; i++)
        inv[i] = mult(inv[i - 1], pw_inv, mod);
}
 
int build(string s){
    int n = s.length();
    int k= 0;
    for(int i = 0; i < n ; ++i){
       k = add((i == 0) ? 0 : k, mult(pw[i], s[i] - 'a' + 1, mod), mod);
    }
    return k;
}
 
int getHash(int x , int y, int H[N]){
    int res = add(H[y], (x == 0) ? 0 : -H[x - 1], mod);
    res = mult(res , (x == 0) ? 1 : inv[x], mod);
    return res;
}

void fnc()
{
    int n;
    cin>>n;
    precalc();
    string a[n];
    int H[n];
    unordered_map<int,int> m;
    FOR(i,0,n)
    {
        cin>>a[i];
        H[i] = build(a[i]);
        m[H[i]]=1;
    }

    int ans=0;

    FOR(i,0,n-1)
        FOR(j,i+1,n)
        {
            int s1 = H[j]-(a[j][0]-a[i][0]);
            if (m[s1]==1)
                continue;
            int s2 = H[i]-(a[i][0]-a[j][0]);
            if ( m[s2]!=1 )
                ans+=2;
        }
    cout<<ans;
}

int main(){
    FIO;
    int n;
    cin>>n;
    FOR(i,0,n)
    {
        fnc();
        cout<<"\n";
    }
}

Can somebody help me, why this didn’t pass the second last test case of the Subtask-2? I got TLE. Please let me know what I am doing wrong. If O(n^2) is fine in the Editorial, then it must be fine for me as well!

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main
{
    public static void main(String[] args)
    {
        FastReader sc=new FastReader();
          int t=sc.nextInt();
          while(t-- > 0)
        {int n=sc.nextInt();
        int count=0;
            HashSet<String> set=new HashSet<>(n);
          String input=sc.nextLine();
          String[] inputs;
          inputs=input.split(" ");
          for(String a:inputs)
           set.add(a);
            //System.out.println(set);
            //System.out.println("All pair possible!");
          for(int i=0;i<n;i++)
          {
              for(int j=0;j<n;j++)
              {
                  if(i!=j)
                  {
                      StringBuilder a= new StringBuilder(inputs[i]);
                      StringBuilder b = new StringBuilder(inputs[j]);
                      //debugging System.out.println(a.toString()+" "+b.toString());
                      a.setCharAt(0,inputs[j].charAt(0));
                      b.setCharAt(0,inputs[i].charAt(0));
                      //debugging System.out.println("Not Funny Test Candidates+"+a.toString()+" "+b.toString());
                      boolean notfunny= set.contains(a.toString())== false && set.contains(b.toString())==false;
                      if(notfunny)
                      {
                          count++;
                      }
                  }
              }
          }

            System.out.println(count);

        }
    }//main ends here
    //FastReader Integration

    static class FastReader
    {
        BufferedReader br;
        StringTokenizer st;

        public FastReader()
        {
            br = new BufferedReader(new
                    InputStreamReader(System.in));
        }

        String next()
        {
            while (st == null || !st.hasMoreElements())
            {
                try
                {
                    st = new StringTokenizer(br.readLine());
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt()
        {
            return Integer.parseInt(next());
        }

        long nextLong()
        {
            return Long.parseLong(next());
        }

        double nextDouble()
        {
            return Double.parseDouble(next());
        }

        String nextLine()
        {
            String str = "";
            try
            {
                str = br.readLine();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return str;
        }
    }//Fast Reader

}//class

1 Like

I guess your solution is slowing down due the .substr() function(especially the string concatenation step in the bool same() function) by testing your code against some large input, portion wise. Sorry I don’t know a quick fix for this…

t=int(input())
while t>0:
n=int(input())
l=list(map(str,input().split()))
k=dict.fromkeys(l,1)
k1={}
k2={}
for i in l:
try:
k1[i[1:]]+=1
k2[i[1:]].add(i[0])
except KeyError:
k1[i[1:]]=1
k2[i[1:]]={i[0]}
ans=0
for i in k2:
for j in k2:
c=len(k2[i].intersection(k2[j]))
c1=len(k2[j].intersection(k2[i]))
ans+=(k1[i]-c)*(k1[j]-c1)
print(ans)

t-=1
  1. List item

Bro, I guess editorial is talking about O(26 *26 *N) in last loop, before that it has sort which will be O(|si|*n*logn) , please check setter’s solution , effectively editor solution is O(NLogN) around, while yours is O(N^2), which will jump out of 10^8 or 10^9 giving TLE for 1 second time limit

Why are we multiplying cnt_10*cnt_01?
ans += cnt_10 * cnt_01;

Can someone please tell me why my solution is giving TLE in one subtask. I am using 2 loops only which will be of O(n^2) and using unordered map which takes O(1) time on an average to traverse.
I am attaching a screenshot of result as well.It would be great help. Thanks in advance.

 #include<bits/stdc++.h>
    using namespace std;
    typedef long long int ll;
    const ll mod =1e9+7; 


    int main()
    {
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);

        #ifndef ONLINE_JUDGE
        freopen("input.txt","r",stdin);
        freopen("output.txt","w",stdout);
        #endif
        
        ll t;
        cin>>t;
        while(t--)
        {
            ll n;
            cin>>n;
            vector<string> v,ans1[30];
            unordered_set<string> alpha[30],words;
            unordered_map<string,ll> m ;
            string s;
            for(ll i=0;i<n;i++)
            {
                cin>>s;
                v.push_back(s);
                m[s]=1;
            }
            ll count = 0;
            ll size = v.size();
            for(ll i=0;i<size;i++)
            {
                for(ll j=i+1;j<size;j++)
                {
                    string a = v[i];
                    string b = v[j];
                    char c = a[0];
                    char d = b[0];
                        a[0] = d;
                        b[0] = c;   
                        if(m[a]!=1&&m[b]!=1)
                        {
                            count+=2;
                        }
                    
                }
            }
            cout<<count<<endl;
        }
        
        return 0;
    }
1 Like

vector S(n);
for (int i = 0; i < n; i++) {
cin >> S[i];
}
//cout<<S[0]<<endl;
vector<pair<string, int>> suffixes;
// Actually, we can divide string in 2 parts - ā€œfirst letterā€ and ā€œall string except first letterā€
for (int i = 0; i < n; i++) {
string suf = ā€œā€;
for (int x = 1; x < (int) S[i].size(); x++) {
suf += S[i][x]; :point_left:
}

how we can access vector to like a 2d vector it is defined as 1d

Hi! S is vector of string, so it is literally 2d vector defined as 1d :slight_smile:

can u please elaborate or give ex. or text where i can read about this
that if we defined vector of string (it will work as 2d )

i created 2 sets 1 containing all the first letters and the second containing all the sub-strings without the first letter. so using the product rule(PnC) the answer should be n(Set-1)*n(Set-2) - the number of funny names.

My solution passes all the test cases, can someone suggest why i’m not able to pass this.

#include
#include
using namespace std;
int main()
{
long long T;
cin >> T;
long long t = T;
long long arr[t];
long long I = 0;

while (T--)
{
    long long N;
    cin >> N;
    set<char> Ch;
    set<string> St;
    string W[N];

    for (long long i = 0; i < N; i++)
    {
        cin >> W[i];
    }
    for (long long i = 0; i < N; i++)
    {
        Ch.insert(W[i][0]);
        St.insert(W[i].substr(1));
    }
    arr[I++] = Ch.size() * St.size() - N;
}
for (long long i = 0; i < t; i++)
{
    cout << arr[i] << endl;
}

}

Man I did the same thing and still got TLE on 2nd last. Even I used O(n^2)
Someone help

The solution in the editorial is O(n log(n)). If you have O(n^2) it will not work. Just in case someone else falls in to this trap :slight_smile:

It’s showing TLE in last 2 test cases , can anyone help me with it

#include<bits/stdc++.h>
using namespace std;

int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t,n;
char a,b;
cin>>t;
while(t–)
{
cin>>n;
vectors;
string a1,b1,aa;
for(int i=0 ; i<n ; i++)
{
cin>>aa;
s.push_back(aa);
}
int count=0;
for(int i=0 ; i<n-1 ; i++)
{
for(int j=i+1 ; j<n ; j++)
{
a=s[i][0];
b=s[j][0];
a1=s[i];
b1=s[j];
a1[0]=b;
b1[0]=a;
if(s[i][0]!=s[j][0] && (find(s.begin() , s.end() , a1) == s.end() && find(s.begin() , s.end() , b1) == s.end()))
count=count+1;
}
}
count=2*count;
cout<<count<<"\n";
}
return 0;
}

Python Snippet . The guy in the video explains much clearer than the script below :grinning:

test = int(input())
for _ in range(test):
    n = int(input())
    arr =  input().split()
    suffixDict ={}
    for i in arr:
        if suffixDict.get(i[1:])== None:
            suffixDict[i[1:]]=[i[0]]
        else:
            suffixDict[i[1:]].append(i[0])
   
    ans=0
    iteratingArray =list( suffixDict.keys())
    for i in range(len(iteratingArray)):
        for j in range(i+1,len(iteratingArray)):
            setA = set(suffixDict[iteratingArray[i]])
            setB = set(suffixDict[iteratingArray[j]])
            comm = len(setA.intersection(setB))
            ans+= 2* (len(setA)-comm) * (len(setB)-comm)
            
    print(ans)

Alternate approach-
Given problem can be solved using bit set as well-

  1. We give distinct bit id to each prefix alphabet( e.g let x=1 b=10 c=100 etc in case we have 3 alphabets in prefixes)

  2. We maintain a map of suffixes where <suffix, val>, here val is an integer bitset and 1 bit represents prefixes that make funny word so if we have a funny words xbad, bbad; then ā€˜bad’ suffix will have val as 011 (continuing from example in point 1 taking 'x’and ā€˜b’ will result in funny word [hence bit 1 and 2 is set to 1] while taking ā€˜c’ will not so 3rd bit which belongs to ā€˜c’ is 0)

  3. Then we iterate over set of distinct suffixes (let it be suffix) and take its XOR with all other suffixes (let it be suffix1)
    , let it be called res (result)

  4. We take then take AND of res&suffix and call it m, and similarly res&suffix1 and call it n, then number of possible solutions between given pair of suffixes is bit_count(m)*bit_count(n) ( bit_count(n)bit_count(m) is taken next time when same pair is taken in reverse order)
    eg-
    let suffix ā€˜bad’ has val of suffix is 1010101
    and ā€˜cat’ has value of suffix1 val 1111100 then
    res is 0101001
    and m=0000001 & n=0101000 so possible ways is bit count(m)
    bit count(n)
    2 * 1 is our answer for given pair

  5. We add this value to count and print the result once all pairs is done
    O(sufixf^2) is time complexity achieved

    Python solution- CodeChef: Practical coding for everyone

great approach…

Time complexity is not O(n^2) in editorial

my O(n^2) solution gives TLE
https://www.codechef.com/viewsolution/48245664