2016 ACM/ICPC Asia Regional Dalian Online
自己还是太菜,补题离不开题解。。。
但还是留个博客,万一以后忘了。。。
1001 Different Circle Permutation
Polya定理,第一次遇见,学习了一下。不旋转的时候可以得到 f[i]=f[i-1]+f[i-2] 斐波那契数列,旋转后就可以通过burnside引理求解,循环节为 gcd(i,n)。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const LL mod=1e9+7; 5 LL pow_mod(LL a,LL n){ 6 LL res=1,t=a%mod; 7 while(n){ 8 if(n&1) res=(res*t)%mod; 9 t=(t*t)%mod; 10 n/=2; 11 } 12 return res; 13 } 14 struct Mat{ 15 LL a[2][2]; 16 void init(){ 17 a[0][0]=1; 18 a[1][0]=a[0][1]=1; 19 a[1][1]=0; 20 } 21 }; 22 Mat operator *(Mat a,Mat b){ 23 Mat c; 24 for(LL i=0;i<2;i++) 25 for(LL j=0;j<2;j++){ 26 c.a[i][j]=0; 27 for(LL k=0;k<2;k++) 28 c.a[i][j]+=a.a[i][k]*b.a[k][j]; 29 c.a[i][j]%=mod; 30 } 31 return c; 32 } 33 Mat operator ^(Mat p,LL k){ 34 Mat ans; ans.init(); 35 while(k){ 36 if(k&1) 37 ans=ans*p; 38 k/=2; 39 p=p*p; 40 } 41 return ans; 42 } 43 LL fun(LL x){ 44 Mat a; a.init(); 45 Mat b; 46 b.a[0][0]=1; 47 b.a[0][1]=0; 48 b.a[1][0]=2; 49 b.a[1][1]=0; 50 a=a^(x-2); 51 if(x>1) b=a*b; 52 return b.a[0][0]; 53 } 54 LL n; 55 LL euler(LL n){ 56 LL ans=n; 57 for(LL i=2;i*i<=n;i++){ 58 if(n%i==0){ 59 ans-=ans/i; 60 while(n%i==0) n/=i; 61 } 62 } 63 if(n>1) ans-=ans/n; 64 return ans; 65 } 66 int main(){ 67 while(~scanf("%lld",&n)){ 68 if(n==1){ 69 printf("%lld\n",2); 70 continue; 71 } 72 LL ans=0; 73 for(LL i=1;i*i<=n;i++){ 74 if(n%i==0){ 75 ans+=fun(i)*euler(n/i)%mod; 76 if(n/i!=i) ans+=fun(n/i)*euler(i)%mod; 77 ans%=mod; 78 } 79 } 80 ans=ans*pow_mod(n,mod-2)%mod; 81 printf("%lld\n",ans); 82 } 83 84 return 0; 85 }
1002 Different GCD Subarray Query
查询区间内不同gcd个数,区间gcd可以ST表打出,并提前二分处理出每个点向右gcd下降的地方。查询作为点对,以右端点大小排序,然后用树状数组处理。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int n,q; 5 int k[100005]; 6 7 int kk; 8 struct node{ 9 int l,r,pos; 10 } a[100005]; 11 bool cmp(node x,node y){ 12 return x.r<y.r; 13 } 14 15 int gcd(int x,int y){ 16 return y==0?x:gcd(y,x%y); 17 } 18 19 int lg[100005]; 20 int dp[100005][35]; 21 int RMQ_ST(int n){ 22 for(int i=1;i<=n;i++) lg[i]=(int)( log(1.0*i)/log(2.0) ); 23 for(int i=1;i<=n;i++) dp[i][0]=k[i]; 24 for(int j=1;(1<<j)<=n;j++){ 25 for(int i=1;i<=n-(1<<j)+1;i++){ 26 dp[i][j]=gcd( dp[i][j-1],dp[i+(1<<(j-1))][j-1] ); 27 } 28 } 29 } 30 int find_gcd(int l,int r){ 31 int k=lg[r-l+1]; 32 return gcd(dp[l][k],dp[r-(1<<k)+1][k]); 33 } 34 35 int ans[100005]; 36 int c[100006]; 37 vector<int> vr[100005]; 38 39 int lowbit(int x){ 40 return x&(-x); 41 } 42 int add(int pos,int val){ 43 for(int i=pos;i<=n;i+=lowbit(i)){ 44 c[i]+=val; 45 } 46 } 47 int sum(int pos){ 48 int res=0; 49 for(int i=pos;i>0;i-=lowbit(i)){ 50 res+=c[i]; 51 } 52 return res; 53 } 54 55 void init(){ 56 for(int i=1;i<=n;i++){ 57 vr[i].push_back(i); 58 int tmp=k[i]; 59 int l=1,r=i; 60 while(l<r){ 61 int L=l,R=r,flag=0; 62 while(L<R){ 63 int mid=(L+R+1)/2; 64 if(find_gcd(mid,i)<tmp) L=mid; 65 else if(find_gcd(l,i)<tmp) R=mid-1; 66 else { flag=1;break; } 67 } 68 if(!flag){ 69 tmp=find_gcd(R,i); 70 vr[i].push_back(R); 71 } 72 else break; 73 r=R; 74 } 75 } 76 } 77 int pos[1000006]; 78 void solve(){ 79 int R=0; 80 for(int i=1;i<=q;i++){ 81 while(R<a[i].r){ 82 R++; 83 for(int j=0;j<vr[R].size();j++){ 84 int ll=vr[R][j]; 85 int _gcd=find_gcd(ll,R); 86 if(pos[_gcd]==0) add(ll,1); 87 else if(pos[_gcd]<ll) add(ll,1),add(pos[_gcd],-1); 88 pos[_gcd]=max(pos[_gcd],ll); 89 } 90 } 91 ans[a[i].pos]=sum(a[i].r)-sum(a[i].l-1); 92 } 93 } 94 95 int main(){ 96 while(scanf("%d%d",&n,&q)!=EOF){ 97 for(int i=1;i<=n;i++) scanf("%d",&k[i]); 98 RMQ_ST(n); 99 init(); 100 kk=sqrt(n); 101 for(int i=1;i<=q;i++){ 102 scanf("%d%d",&a[i].l,&a[i].r); 103 a[i].pos=i; 104 } 105 sort(a+1,a+1+q,cmp); 106 memset(c,0,sizeof(c)); 107 memset(pos,0,sizeof(pos)); 108 //cout<<sum(1)<<endl; 109 solve(); 110 for(int i=1;i<=q;i++) printf("%d\n",ans[i]); 111 } 112 113 114 return 0; 115 } 116 /* 117 9 10 118 3 3 4 4 4 6 6 6 9 119 */
1003 Alice's Adventure in Wonderland
1004 Number of Connected Subgraph
排序后判断前 i 个和不能少于 i*(i-1)/2 ,且总数为 n*(n-1)/2 即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 int n; 4 int b[20005]; 5 int main(){ 6 int t; 7 while(cin>>t){ 8 while(t--){ 9 cin>>n; 10 for(int i=1;i<=n;i++) cin>>b[i]; 11 int sum=0,flag=0; 12 for(int i=1;i<=n;i++){ 13 sum+=b[i]; 14 if(sum<i*(i-1)) flag=1; 15 } 16 if(sum!=n*(n-1)) flag=1; 17 if(flag==0) cout<<'T'<<endl; 18 else cout<<'F'<<endl; 19 } 20 } 21 22 return 0; 23 }
最多的情况为把所有人平均分成两组,然后内部互为敌人,外部互为朋友即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 long long n,m; 4 int main(){ 5 while(cin>>n>>m){ 6 if(m>=(n-n/2)*(n/2)) cout<<"T"<<endl; 7 else cout<<"F"<<endl; 8 } 9 10 return 0; 11 }
查询区间最左边的一个数向右取模后的结果,每次取模下降至少为一半,所以ST表打出最小值,然后对每个询问依次二分出向右的第一个比当前值小的位置。
1 #include <bits/stdc++.h> 2 using namespace std; 3 int n,m; 4 int a[100005]; 5 int dp[100005][35]; 6 int lg[100005]; 7 void RMQ_ST(int n){ 8 for(int i=1;i<=n;i++) lg[i]=(int)(log(1.0*i)/log(2.0)); 9 for(int i=1;i<=n;i++) dp[i][0]=a[i]; 10 for(int j=1;(1<<j)<=n;j++){ 11 for(int i=1;i<=n-(1<<j)+1;i++){ 12 dp[i][j]=min( dp[i][j-1],dp[i+(1<<(j-1))][j-1] ); 13 } 14 } 15 } 16 int find_min(int l,int r){ 17 int k=lg[r-l+1]; 18 return min(dp[l][k],dp[r-(1<<k)+1][k]); 19 } 20 void solve(int l,int r){ 21 int res=a[l]; 22 int L=l+1,R=r; 23 while(l<r){ 24 while(L<R){ 25 int mid=(L+R)/2; 26 if(find_min(l+1,mid)<=res) R=mid; 27 else L=mid+1; 28 } 29 if(find_min(l+1,L)>res) L=R; 30 res%=a[L]; 31 L++; R=r; 32 if(find_min(l+1,r)>res) break; 33 } 34 printf("%d\n",res); 35 } 36 int main(){ 37 int t; 38 scanf("%d",&t); 39 while(t--){ 40 scanf("%d",&n); 41 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 42 RMQ_ST(n); 43 scanf("%d",&m); 44 while(m--){ 45 int l,r; 46 scanf("%d%d",&l,&r); 47 solve(l,r); 48 } 49 } 50 51 return 0; 52 } 53 /* 54 6 55 18 30 15 8 6 4 56 */
补图最短路,用两个set维护还没有记录的点,和与当前点相连的点。
#include <bits/stdc++.h> using namespace std; vector<int> g[200005]; int dis[200005]; int n,m,s; int u,v; void bfs(){ queue<int> q; q.push(s); set<int> s1,s2; for(int i=1;i<=n;i++) if(i!=s) s1.insert(i); while(!q.empty()){ int u=q.front(); q.pop(); for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(s1.find(v)!=s1.end()){ s1.erase(v); s2.insert(v); } } set<int>::iterator it=s1.begin(); for(;it!=s1.end();it++){ dis[(*it)]=dis[u]+1; q.push(*it); } swap(s1,s2); s2.clear(); } vector<int> ans; for(int i=1;i<=n;i++) if(i!=s) ans.push_back(dis[i]); for(int i=0;i<ans.size();i++){ if(i==0) printf("%d",ans[i]); else printf(" %d",ans[i]); } printf("\n"); } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); memset(dis,-1,sizeof(dis)); for(int i=1;i<=n;i++) g[i].clear(); for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } scanf("%d",&s); dis[s]=0; bfs(); } return 0; } /* 2 5 6 1 2 1 3 2 4 3 4 2 5 4 5 2 */
离散化后dfs,用树状数组记录每个数出现个数,然后直接计数,当处理完一个点的时候要把这个这个值删除。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 LL n,k; 5 LL root; 6 LL a[100005]; 7 LL in[100005]; 8 vector<LL> g[100005]; 9 LL cnt; 10 LL c[500005]; 11 LL lowbit(LL x){ 12 return x&(-x); 13 } 14 void add(LL pos,LL val){ 15 for(LL i=pos;i<=cnt;i+=lowbit(i)){ 16 c[i]+=val; 17 } 18 } 19 LL sum(LL pos){ 20 LL res=0; 21 for(LL i=pos;i>0;i-=lowbit(i)){ 22 res+=c[i]; 23 } 24 return res; 25 } 26 vector<LL> v; 27 LL getid(LL x){ 28 return lower_bound(v.begin(),v.end(),x)-v.begin()+1; 29 } 30 31 LL ans; 32 void dfs(LL u){ 33 LL id=getid(a[u]); 34 if(a[u]){ 35 ans+=sum(getid(k/a[u])); 36 add(id,1); 37 } 38 else{ 39 ans+=sum(cnt); 40 add(1,1); 41 } 42 for(LL i=0;i<g[u].size();i++){ 43 dfs(g[u][i]); 44 } 45 if(a[u]) add(id,-1); 46 else add(1,-1); 47 } 48 int main(){ 49 LL t; 50 scanf("%lld",&t); 51 while(t--){ 52 v.clear(); v.push_back(0); 53 memset(c,0,sizeof(c)); 54 memset(in,0,sizeof(in)); 55 scanf("%lld%lld",&n,&k); 56 for(LL i=1;i<=n;i++){ 57 g[i].clear(); 58 scanf("%lld",&a[i]); 59 v.push_back(a[i]); 60 if(a[i]!=0) v.push_back(k/a[i]); 61 } 62 for(LL i=1;i<n;i++){ 63 LL u,v; 64 scanf("%lld%lld",&u,&v); 65 g[u].push_back(v); 66 in[v]++; 67 } 68 sort(v.begin(),v.end()); 69 v.erase(unique(v.begin(),v.end()),v.end()); 70 cnt=v.size(); ans=0; 71 for(LL i=1;i<=n;i++){ 72 if(in[i]==0) root=i; 73 } 74 dfs(root); 75 printf("%lld\n",ans); 76 } 77 78 79 return 0; 80 }