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
",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
",ans);
82     }
83 
84     return 0;
85 }
Psong

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
",ans[i]);
111     }
112 
113 
114     return 0;
115 }
116 /*
117 9 10
118 3 3 4 4 4 6 6 6 9
119 */
Psong

1003 Alice's Adventure in Wonderland

1004 Number of Connected Subgraph

1005 Seats

1006 Football Games

排序后判断前 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 }
Psong

1007 Friends and Enemies

最多的情况为把所有人平均分成两组,然后内部互为敌人,外部互为朋友即可。

 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 }
Psong

1008 Function

查询区间最左边的一个数向右取模后的结果,每次取模下降至少为一半,所以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
",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 */
Psong

1009 Sparse Graph

补图最短路,用两个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("
");
}
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
*/
Psong

1010 Weak Pair

离散化后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
",ans);
76     }
77 
78 
79     return 0;
80 }
Psong
原文地址:https://www.cnblogs.com/N-Psong/p/7141906.html