Submission #1270317

#TimeUsernameProblemLanguageResultExecution timeMemory
1270317newbie_tOsmosmjerka (COCI17_osmosmjerka)C++20
160 / 160
2057 ms39568 KiB
#define _GLIBCXX_FILESYSTEM #include <bits/stdc++.h> #define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); #define F first #define S second #define int long long using namespace std; // our goal is to generate all the possible unique strings and their counts // i generate all the possible strings, but string can go up to 1e9 so I generate only the pattern // by pattern I mean for example "abcabc" this string pattern is "abc" // so we can just generate the pattern and store their values in a map however there is a problem // the pattern generated are not all of the same size so lets say that k is very big and we only generated the patterns // we can have a pattern of "aba" and another of "ab" // we will miss that this "ab" is the same as this "aba" because we didn't continue and we had to stop when we are just repeating the pattern // so the solution is to find the pattern and calculate it's hash function and calculate it's k-length version by just calculating a geometric series int n,m,k; int b=3137; int mod=(1ll<<61)-1; map<int,int> mp; vector<__int128> p(502*530); int pows(__int128 x,__int128 y) { __int128 ans=1; while(y) { if(y%2) ans=(ans*x)%mod; y/=2; x=(x*x)%mod; } return ans; } int hash_len(int start,vector<__int128> &h,int len) // this function just calculate the hash for the pattern { int sz=h.size(); int l1,l2,r1,r2; l1=l2=r1=r2=-1; l1=start; r1 =min(sz-1,start+len-1); if(r1-l1+1 <len) { l2=0; int need=len-(r1-l1+1); r2=need-1; } int value=0; if(l2==-1) { if(l1==0) value=h[r1]; else value=(h[r1]-(h[l1-1]*p[r1-l1+1])%mod); if(value<0)value+=mod; } else { int value1=h[r1]-((h[l1-1]*p[r1-l1+1])%mod); int value2=h[r2]; if(value1<0)value1+=mod; value=((value1*p[r2+1]%mod)+value2)%mod; } return value; } void roh(string x) // this function generates the pattern and calculate it's k-hashed version with geometric series { int sz=min((int)x.size(),k); vector<__int128> h(x.size()); h[0]=x[0]; for(int i=1; i<x.size(); i++) h[i]=(h[i-1]*b+x[i])%mod; for(int i=0; i<x.size(); i++) { int value=hash_len(i,h,sz); if(sz!=k) { // geometric series int rem=k%sz; int q=k/sz; int r=p[sz]; __int128 num=1-(pows(r,q))+mod; num=(value*num)%mod; __int128 den=pows((1-r+mod),mod-2); __int128 ans=(num*den)%mod; value=ans; if(rem!=0) { int hash_of_reminder=hash_len(i,h,rem); value=((ans*p[rem])%mod+hash_of_reminder)%mod; } } mp[value]++; } } int vis[502][502]; signed main() { IOS cin>>n>>m>>k; vector<vector<char>> grid(n,vector<char>(m)); for(int i=0; i<n; i++) for(int j=0; j<m; j++) cin>>grid[i][j]; p[0]=1; for(int i=1; i<=n*m+10; i++) p[i]=(p[i-1]*b)%mod; //example: //abc //def //lets say we want to generate the strings from going to the right only in the first row then we will make "abc" // now this "abc" can be used to calculate the pattern for the whole row for a and b and for c //for b is "bca" //for c it's cab //so it's just a cycles from the original string "abc" // also if I want to go the other direction (left) I can just inverse the string and make it cba int di[]= {-1,-1,0,1}; // so here i only go 4 directions because I will reverse the string generated which will just represent the other direction int dj[]= {1,-1,1,0}; for(int d=0; d<4; d++) { memset(vis,0,sizeof(vis)); for(int i=0; i<n; i++) { for(int j=0; j<m; j++) { if(!vis[i][j]) { vis[i][j]=true; string x; x.push_back(grid[i][j]); int ii,jj; ii=i; jj=j; while(true) // keep moving till you get back to where you started { ii=(ii+di[d]+n)%n; jj=(jj+dj[d]+m)%m; if(ii==i && jj==j)break; vis[ii][jj]=true; x.push_back(grid[ii][jj]); } roh(x); reverse(x.begin(),x.end()); roh(x); } } } } int num,den; num=0; den=n*m*8*n*m*8; for(auto [a,b]:mp) { num+= (b*b); } int g=gcd(num,den); cout<<(num/g)<<"/"<<(den/g); }
#Verdict Execution timeMemoryGrader output
Fetching results...