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 }