結果
問題 | No.1660 Matrix Exponentiation |
ユーザー | kiyoshi0205 |
提出日時 | 2021-08-27 22:12:19 |
言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 71 ms / 2,000 ms |
コード長 | 12,445 bytes |
コンパイル時間 | 3,217 ms |
コンパイル使用メモリ | 211,456 KB |
実行使用メモリ | 30,508 KB |
最終ジャッジ日時 | 2024-11-21 02:47:52 |
合計ジャッジ時間 | 4,743 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 27 |
コンパイルメッセージ
main.cpp: In function 'int main()': main.cpp:383:12: warning: structured bindings only available with '-std=c++17' or '-std=gnu++17' [-Wc++17-extensions] 383 | for(auto&[a,b]:edge){ | ^
ソースコード
#pragma GCC target("avx") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") #include<bits/stdc++.h> // #include<ext/pb_ds/assoc_container.hpp> // #include<ext/pb_ds/tree_policy.hpp> // #include<ext/pb_ds/tag_and_trait.hpp> // using namespace __gnu_pbds; // #include<boost/multiprecision/cpp_int.hpp> // namespace multiprecisioninteger = boost::multiprecision; // using cint=multiprecisioninteger::cpp_int; using namespace std; using ll=long long; using datas=pair<ll,ll>; using ddatas=pair<long double,long double>; using tdata=pair<ll,datas>; using vec=vector<ll>; using mat=vector<vec>; using pvec=vector<datas>; using pmat=vector<pvec>; // using llset=tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>; #define For(i,a,b) for(i=a;i<(ll)b;++i) #define bFor(i,b,a) for(i=b,--i;i>=(ll)a;--i) #define rep(i,N) For(i,0,N) #define rep1(i,N) For(i,1,N) #define brep(i,N) bFor(i,N,0) #define brep1(i,N) bFor(i,N,1) #define all(v) (v).begin(),(v).end() #define allr(v) (v).rbegin(),(v).rend() #define vsort(v) sort(all(v)) #define vrsort(v) sort(allr(v)) #define uniq(v) vsort(v),(v).erase(unique(all(v)),(v).end()) #define endl "\n" #define popcount __builtin_popcountll #define eb emplace_back #define print(x) cout<<x<<endl #define printyes print("Yes") #define printno print("No") #define printYES print("YES") #define printNO print("NO") #define output(v) do{bool f=0;for(auto outi:v){cout<<(f?" ":"")<<outi;f=1;}cout<<endl;}while(0) #define matoutput(v) do{for(auto outimat:v)output(outimat);}while(0) constexpr ll mod=1000000007; // constexpr ll mod=998244353; constexpr ll inf=1LL<<60; constexpr long double eps=1e-9; const long double PI=acosl(-1); template<class T,class E> ostream& operator<<(ostream& os,const pair<T,E>& p){return os<<"("<<p.first<<","<<p.second<<")";} template<class T> ostream& operator<<(ostream& os,const vector<T>& v){ os<<"{";bool f=false; for(auto& x:v){if(f)os<<",";os<<x;f=true;} os<<"}"; return os; } template<class T> ostream& operator<<(ostream& os,const set<T>& v){ os<<"{";bool f=false; for(auto& x:v){if(f)os<<",";os<<x;f=true;} os<<"}"; return os; } template<class T> ostream& operator<<(ostream& os,const multiset<T>& v){ os<<"{";bool f=false; for(auto& x:v){if(f)os<<",";os<<x;f=true;} os<<"}"; return os; } template<class T,class E> ostream& operator<<(ostream& os,const map<T,E>& v){ os<<"{";bool f=false; for(auto& x:v){if(f)os<<",";os<<x;f=true;} os<<"}"; return os; } template<class T> inline bool chmax(T& a,const T b){bool x=a<b;if(x)a=b;return x;} template<class T> inline bool chmin(T& a,const T b){bool x=a>b;if(x)a=b;return x;} #ifdef DEBUG void debugg(){cout<<endl;} template<class T,class... Args>void debugg(const T& x,const Args&... args){cout<<" "<<x;debugg(args...);} #define debug(...) cout<<__LINE__<<" ["<<#__VA_ARGS__<<"]:",debugg(__VA_ARGS__) #else #define debug(...) (void(0)) #endif inline void startupcpp(void) noexcept{ cin.tie(0); ios::sync_with_stdio(false); cout<<fixed<<setprecision(15); } ll modinv(ll a,const ll m=mod) noexcept{ ll b=m,u=1,v=0,t; while(b){ t=a/b; a-=t*b; swap(a,b); u-=t*v; swap(u,v); } return (u+m)%m; } ll moddevide(const ll a,const ll b) noexcept{return (a*modinv(b))%mod;} vec modncrlistp,modncrlistm; ll modncr(const ll n,const ll r) noexcept{ if(n<r)return 0; ll i,size=modncrlistp.size(); if(size<=n){ modncrlistp.resize(n+1); modncrlistm.resize(n+1); if(!size){ modncrlistp[0]=modncrlistm[0]=1; size++; } For(i,size,n+1)modncrlistp[i]=modncrlistp[i-1]*i%mod; modncrlistm[n]=modinv(modncrlistp[n]); for(i=n;i>size;--i)modncrlistm[i-1]=modncrlistm[i]*i%mod; } return modncrlistp[n]*modncrlistm[r]%mod*modncrlistm[n-r]%mod; } ll modpow(ll a,ll n,const ll m=mod){ if(n<0)return 0; ll res=1; while(n>0){ if(n&1)res=res*a%m; a=a*a%m; n>>=1; } return res; } constexpr ll gcd(const ll a,const ll b) noexcept{return (!b)?abs(a):(a%b==0)?abs(b):gcd(b,a%b);} constexpr ll lcm(const ll a,const ll b) noexcept{return a/gcd(a,b)*b;} struct countingprime{ public: countingprime(long long N):N(N),N2(sqrtl(N)),N3(cbrtl(N)),N6(sqrtl(N3)),valsize(0),primesize(0){ assert(N>0); solve(); } ~countingprime(){delete[] pi;} //return π(N/k) long long calc(int k=1){ assert(1<=k&&k<=N); return pi[index(N/k)]; } private: long long *val,*pi,*BIT,N,N2,N3,N6; int *prime; size_t valsize,primesize,BITsize; //x≦val[i]を満たす最大のiを返す(x<1,x>Nは壊れる) size_t index(long long x){return x<=N2?valsize-x:N/x-1;} //BITに最小素因数がN^{1/6}以上の合成数now(<N/∛N)を追加するクエリ //N^{1/6}*√N=N^{2/3}>=N/∛Nであるから列挙に必要な素数は√N以下の物のみで足りていることに注意 void update(unsigned int id,long long now){ if(prime[id]!=now){ //合成数となる時 for(size_t j=valsize-index(now);j<BITsize;j+=-j&j)++BIT[j]; } //nowの倍数を追加する while(id<primesize&&now*prime[id]<N/N3){ update(id,now*prime[id]); ++id; } } void solve(){ { //val,pi,prime(√N以下)の初期化 //val={floor(N/i)|1≦i≦N}を重複を取り除き降順に並び替えたもの //pi:π(val[i])にしたい、初期化はpi[i]=val[i]で for(long long now=N;now;now=N/(N/now+1))++valsize; val=new long long[valsize]; pi=new long long[valsize]; valsize=0; for(long long now=N;now;now=N/(N/now+1)){ val[valsize]=pi[valsize]=now; valsize++; } bool *isprime=new bool[N2+1]; memset(isprime+2,1,N2-1); for(int i=2;i*i<=N2;++i){ if(isprime[i])for(int j=i*i;j<=N2;j+=i)isprime[j]=false; } for(int i=2;i<=N2;++i)if(isprime[i])++primesize; prime=new int[primesize]; primesize=0; for(int i=2;i<=N2;++i)if(isprime[i])prime[primesize++]=i; delete[] isprime; } //単純にエラトステネスの篩と同じように小さい素数から篩っていく //dp[j]-=dp[j/prime[i]]みたいなことをすればいい(値が飛び飛びなので適宜調整する(この調整自体はO(1)でできる)) //完全愚直でやると√N*π(√N)=O(N/log N),700msくらい(π(N)=O(N/log N)に注意) //BITを上手く使うとO(N^{2/3})となる size_t see=0; { //愚直に更新する(p≦N^{1/6}) //π(N^{1/6})*2√N=O(N^{2/3}/log N) while(see<primesize&&prime[see]<=N6){ for(size_t i=0;prime[see]<=val[i]/prime[see];++i){ pi[i]-=pi[index(val[i]/prime[see])]-see-1; } ++see; } } { //BITを使う(N^{1/6}<p<∛N) BITsize=valsize-N3+1; BIT=new long long[BITsize]; memset(BIT,0,sizeof(long long)*BITsize); while(see<primesize&&prime[see]<N3){ //大きい方N3個の変更クエリ(BITのsumクエリ) //∛N*(π(∛N)-π(N^{1/6})=O(N^{2/3}/log N)回BITでクエリを回すので //O(N^{2/3}) for(size_t i=0;(int)i<N3&&prime[see]<=val[i]/prime[see];++i){ size_t j=index(val[i]/prime[see]); long long x=pi[j]-see-1; if((int)j>=N3)for(j=valsize-j;j>0;j-=-j&j)x-=BIT[j]; pi[i]-=x; } //小さい方valsize-N3個の変更クエリ(BITのaddクエリ) //addする対称はN/N3以下であって最小素因数がN^{1/6}より大きい合成数の個数に等しい //これはO(N^{2/3})個BITで回すのでO(N^{2/3}log N)(実はlogが落ちているらしいが良く分からないし#logは定数 なのでヨシ!) update(see,prime[see]); ++see; } //BITに貯め込んだ分の精算 for(size_t i=1;i<BITsize;++i){ BIT[i]+=BIT[i-(-i&i)]; pi[valsize-i]-=BIT[i]; } delete[] BIT; } { //愚直に更新する(∛N≦p≦√N) //実はO(N^{2/3}/log N) //(∵)Σ(∛N≦p≦√N,p:prime)#{i|p≦val[i]/p}=Σ(∛N≦p≦√N,p:prime)#{i|p^2≦val[i]} // ∛N≦pより,p^2>val[∛N+1]から =Σ(∛N≦p≦√N,p:prime)Σ(0≦i≦∛N)(int)(p^2<=val[i]) // =Σ(∛N≦p≦√N,p:prime)Σ(1≦i≦∛N+1)(int)(p^2<=floor(N/i)) // =Σ(1≦i≦∛N+1)Σ(∛N≦p≦√N,p:prime)(int)(p^2<=floor(N/i)) // =Σ(1≦i≦∛N+1)Σ(∛N≦p≦√N,p:prime)(int)(p<=floor(√(N/i))) // ≦Σ(1≦i≦∛N+1)π(√(N/i)) // =O((√N/log N)Σ(1≦i≦∛N+1)1/√i) // Σ(1≦i≦N)1/√i~∫_1^N 1/√xdx~2√Nより =O((√N/log N)(N^{1/6})) // =O(N^{2/3}/log N) while(see<primesize){ for(size_t i=0;prime[see]<=val[i]/prime[see];++i){ pi[i]-=pi[index(val[i]/prime[see])]-see-1; } ++see; } } //1を取り除く for(size_t i=0;i<valsize;++i)--pi[i]; delete[] val; } }; vec primefactorization(ll N){ ll i=2; vec res; while(i*i<=N){ while(!(N%i)){ res.eb(i); N/=i; } i++; } if(N!=1)res.eb(N); return res; } struct scc_graph{ public: scc_graph(int n):_n(n){} scc_graph(vector<vector<int>> g):_n(g.size()){ for(int i=0;i<_n;++i)for(auto& x:g[i])add_edge(i,x); scc_ids(); } scc_graph(vector<vector<long long>> g):_n(g.size()){ for(int i=0;i<_n;++i)for(auto& x:g[i])add_edge(i,x); scc_ids(); } void add_edge(int from,int to){ assert(0<=from&&from<_n); assert(0<=to&&to<_n); edges.push_back({from,{to}}); } void add_clause(int i,bool f,int j,bool g){ assert(0<=i&&i*2<_n); assert(0<=j&&j*2<_n); add_edge(i<<1|!f,j<<1|g); add_edge(j<<1|!g,i<<1|f); } //n must be *2 vector<bool> solve_twosat(){ if(!group_num)scc_ids(); int m=_n>>1; vector<bool> answer(m); for(int i=0;i<m;++i){ if(ids[i<<1]==ids[i<<1|1])return{}; answer[i]=ids[i<<1]<ids[i<<1|1]; } return answer; } vector<vector<int>> scc(){ if(!group_num)scc_ids(); vector<int> counts(group_num); for(auto& x:ids)counts[x]++; vector<vector<int>> groups(group_num); for(int i=0;i<group_num;++i)groups[i].reserve(counts[i]); for(int i=0;i<_n;++i)groups[ids[i]].push_back(i); return groups; } int size(){return group_num;} int operator[](int k) const{return ids[k];} private: int _n,group_num=0; struct edge{ int to; }; struct csr{ vector<int> start; vector<edge> elist; csr(int n,const vector<pair<int,edge>>& edges):start(n+1),elist(edges.size()){ for(auto& e:edges)++start[e.first+1]; for(int i=0;i<n;++i)start[i+1]+=start[i]; auto counter=start; for(auto& e:edges)elist[counter[e.first]++]=e.second; } }; vector<int> ids; vector<pair<int,edge>> edges; // @return pair of(# of scc,scc id) void scc_ids(){ auto g=csr(_n,edges); int now_ord=0; vector<int> visited,low(_n),ord(_n,-1); ids.resize(_n); visited.reserve(_n); auto dfs=[&](auto self,int v)-> void{ low[v]=ord[v]=now_ord++; visited.push_back(v); for(int i=g.start[v];i<g.start[v+1];++i){ auto to=g.elist[i].to; if(ord[to]==-1){ self(self,to); low[v]=min(low[v],low[to]); }else{ low[v]=min(low[v],ord[to]); } } if(low[v]==ord[v]){ while(true){ int u=visited.back(); visited.pop_back(); ord[u]=_n; ids[u]=group_num; if(u==v)break; } group_num++; } }; for(int i=0;i<_n;++i){ if(ord[i]==-1)dfs(dfs,i); } for(auto& x:ids){ x=group_num-1-x; } } }; ll N,M,K,H,W,A,B,C,D; string s,t; ll ans; int main(){ startupcpp(); // int codeforces;cin>>codeforces;while(codeforces--){ ll i,j; cin>>N>>M; scc_graph g(N); mat sg(N); pvec edge(M); for(auto&[a,b]:edge){ cin>>a>>b; g.add_edge(--a,--b); if(a==b){ print(-1); return 0; } sg[a].emplace_back(b); } auto scc=g.scc(); if(int(scc.size())!=N){ print(-1); return 0; } vec dp(N,1); for(auto v:scc){ auto x=v[0]; for(auto y:sg[x]){ chmax(dp[y],dp[x]+1); } } print(*max_element(all(dp))); }