17-06-28模拟赛

T1:考虑求出所有的环。若该环中点的个数为n,则拆环的方法为为C(1,n)+C(2,n)+...+C(n-1,n)=2n-2种。(全翻转及全不翻转都是环)。

再求出非环节点的个数m,则方法有2m种。(可以发现每个连通块中中必有环,所以可以都不翻转)根据乘法原理,将所有环的方案数及非环节点的方案数相乘即可。

注意要用到快速幂。

Note:注意到每个连通块中有且仅有一个环,进行一次dfs即可。

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define mod 1000000007
 5 #define MN 200005
 6 #define ll long long
 7 using namespace std;
 8 inline int in(){
 9     int x=0;bool f=0; char c;
10     for (;(c=getchar())<'0'||c>'9';f=c=='-');
11     for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0');
12     return f?-x:x;
13 }
14 struct edge{
15     int to,next;
16 }e[MN+5],r[MN+5];
17 int head[MN],rhed[MN],num[MN],ct[MN];
18 int cnt=0,rct=0,tmp,n,a,pos,sum;
19 ll res=1ll,rn;
20 bool vis[MN];
21 inline void ins(int x,int y){
22     ++cnt;e[cnt].to=y;e[cnt].next=head[x];head[x]=cnt;
23     ++rct;r[rct].to=x;r[rct].next=rhed[y];rhed[y]=rct;
24 }
25 inline ll qpow(int x){
26     ll ans=1ll,mul=2ll;
27     while (x){
28         if (x&1) ans=(ans*mul)%mod;
29         mul=(mul*mul)%mod;x>>=1;
30     }return ans;
31 }
32 void dfs(int x){
33     vis[x]=1;
34     for (int i=head[x];i;i=e[i].next){
35         int v=e[i].to;
36         if (!vis[v]) dfs(v);
37     }num[++tmp]=x;
38 }
39 void rdfs(int x,int k){
40     vis[x]=1;++ct[k];
41     for (int i=rhed[x];i;i=r[i].next){
42         int v=r[i].to;
43         if (!vis[v]) rdfs(v,k);
44     }
45 }
46 int main()
47 {
48     n=in();for (int i=1;i<=n;++i) a=in(),ins(i,a);memset(vis,0,sizeof(vis));
49     for (int i=1;i<=n;++i) if (!vis[i]) dfs(i);memset(vis,0,sizeof(vis));
50     for (int i=n;i;--i) if (!vis[num[i]]) rdfs(num[i],++pos);
51     for (int i=1;i<=pos;++i){
52         if (ct[i]<=1) continue;
53         sum+=ct[i];rn=1ll*(qpow(ct[i])-2+mod)%mod;
54         res=1ll*(res*rn)%mod;
55     }if (!sum) printf("%lld
",1ll*(qpow(n)-1+mod)%mod);
56     else {
57         rn=1ll*qpow(n-sum)%mod;res=1ll*(res*rn)%mod;
58         printf("%lld
",res);
59     }return 0;
60 }

 T2:经过推理可知,若经过操作能够使负数的个数为奇数,则应尽可能使乘积的绝对值大,即每次将绝对值最小的数的绝对值+x.

否则使乘积的最小值尽可能小,即每次将绝对值最小的数的绝对值-x.

若开始时负数的个数为奇数,则每次将绝对值最小的数的绝对值+x.

否则考虑能否使负数的个数为奇数,若能,则通过操作将绝对值最小的数变号,再每次将绝对值最小的数的绝对值+x.

若不能,则每次将绝对值最小的数的绝对值-x.

注意对0的特殊处理。绝对值最小的数用堆维护。

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 #include<iostream>
 5 #include<algorithm>
 6 #define inf 0x7fffffff
 7 using namespace std;
 8 typedef pair <int,int> P;
 9 inline int in(){
10     int x=0;bool f=0; char c;
11     for (;(c=getchar())<'0'||c>'9';f=c=='-');
12     for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0');
13     return f?-x:x;
14 }
15 inline int abs(int x){return x>0?x:-x;}
16 int a[200005],nega,posi,n,k,x,pmn,nmx,npos,ppos;
17 priority_queue<P,vector<P>,greater<P> >q;
18 int main()
19 {
20     n=in();k=in();x=in();pmn=inf;nmx=-inf;
21     for (int i=1;i<=n;++i){
22         a[i]=in();q.push(make_pair(abs(a[i]),i));
23         if (a[i]<0) {++nega;if (a[i]>nmx) nmx=a[i],npos=i;}
24         if (a[i]>0) {++posi;if (a[i]<pmn) pmn=a[i],ppos=i;}
25         if (!a[i]&&nmx&&pmn) nmx=pmn=0,npos=ppos=i;
26     }
27     if (nega&1){
28         for (int i=1;i<=k;++i){
29             int t=q.top().first,tpos=q.top().second;q.pop();
30             if (a[tpos]>=0) a[tpos]+=x;else a[tpos]-=x;
31             q.push(make_pair(t+x,tpos));
32         }
33     }else{
34         int d,dpos;
35         if (abs(nmx)<pmn) d=abs(nmx),dpos=npos;else d=abs(pmn),dpos=ppos;
36         if (1ll*d<1ll*x*k){
37             k-=(d/x+1);q.pop();
38             if (a[dpos]>=0) a[dpos]-=(d/x+1)*x;
39             else a[dpos]+=(d/x+1)*x;
40             q.push(make_pair(abs(a[dpos]),dpos));
41             for (int i=1;i<=k;++i){
42                 int t=q.top().first,tpos=q.top().second;q.pop();
43                 if (a[tpos]>=0) a[tpos]+=x;else a[tpos]-=x;
44                 q.push(make_pair(t+x,tpos));
45             }
46         }else {
47             for (int i=1;i<=k;++i){
48                 int t=q.top().first,tpos=q.top().second;q.pop();
49                 if (a[tpos]>=0) a[tpos]-=x;else a[tpos]+=x;
50                 q.push(make_pair(t-x,tpos));
51             }
52         }
53     }for (int i=1;i<=n;++i) printf("%d ",a[i]);return 0;
54 }

T3:

注意到将路变为墙时不会将一个区域分割,也不会将一个只有一格的区域填满,可以发现每块区域都不会被分割或消失,考虑用带权并查集维护一块区域可到达点的个数。

对于初始状态,dfs求出连通块及其点数。

对于查询操作,找到所有点所属连通块的父连通块的点数最大值即可。

对于修墙操作,将该节点所属连通块的父连通块点数减一,并将该节点所属连通块数修改为0.

对于修路操作,将该路设为新连通块,若与该路相连节点为路,则合并该路所属父连通块与该路相连节点所属父连通块。

注意合并时将其中一连通块的权值设为0。

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define MN 1000005
 5 using namespace std;
 6 inline int in(){
 7     int x=0;bool f=0; char c;
 8     for (;(c=getchar())<'0'||c>'9';f=c=='-');
 9     for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0');
10     return f?-x:x;
11 }
12 char mp[MN];
13 int fa[MN<<1],siz[MN<<1],num[MN];
14 int n,m,x,y,q,cnt=0,tp,w;
15 inline int gf(int x){return fa[x]?fa[x]=gf(fa[x]):x;}
16 inline void dfs(int x,int y,int ct){
17     if (mp[x*m+y]!='.'||num[x*m+y]) return;
18     num[x*m+y]=ct;++siz[num[x*m+y]];
19     if (x) dfs(x-1,y,ct);if (y) dfs(x,y-1,ct);
20     if (x+1<n) dfs(x+1,y,ct);if (y+1<m) dfs(x,y+1,ct);
21 }
22 inline void uni(int x,int y,int p,int q){
23     int f1=gf(num[x*m+y]),f2=gf(num[p*m+q]);
24     if (mp[p*m+q]!='.'||f1==f2) return;
25     siz[f2]+=siz[f1];siz[f1]=0;fa[f1]=f2;
26 }
27 
28 int main()
29 {
30     n=in();m=in();memset(fa,0,sizeof(fa));
31     for (int i=0;i<n;++i) scanf("%s",mp+i*m);
32     for (int i=0;i<n;++i)
33     for (int j=0;j<m;++j)
34     if (mp[i*m+j]=='.'&&!num[i*m+j]) dfs(i,j,++cnt);q=in();
35     for (int i=1;i<=q;++i){
36         tp=in();w=in();
37         if (tp==1){
38             int mx=0,pos=1;
39             for (int j=1;j<=w;++j){
40                 x=in()-1;y=in()-1;
41                 if (mp[x*m+y]=='.'&&siz[gf(num[x*m+y])]>mx) mx=siz[gf(num[x*m+y])],pos=j;
42             }printf("%d
",pos);
43         }else for (int j=1;j<=w;++j){
44             x=in()-1;y=in()-1;
45             if (mp[x*m+y]=='.'){
46                 --siz[gf(num[x*m+y])];
47                 mp[x*m+y]='*';num[x*m+y]=0;
48             }else{
49                 num[x*m+y]=++cnt;++siz[num[x*m+y]];mp[x*m+y]='.';
50                 if (x) uni(x,y,x-1,y);if (y) uni(x,y,x,y-1);
51                 if (x+1<n) uni(x,y,x+1,y);if (y+1<m) uni(x,y,x,y+1);
52             }
53         }
54     }return 0;
55 }
原文地址:https://www.cnblogs.com/codingutopia/p/test170628.html