标签:mes 次数 get getchar 一点 etc als ns2 tar
这是最终章,永久的思念。
题目大意:
有N张牌,每张牌两面都有数字,范围都在1到2N之间,求最少的反转次数,使得每张牌朝上的一面的数字各不相同,并求出达到这个效果的方案数。(多测,初始时每张牌正面朝上,无解输出“-1 -1”)
题解:
20%数据(N<=20)
直接搜索即可。
100%数据(N<=1×105)
搜索复杂度不允许,我们试图让这个问题抽象化。
将牌上的数字抽象为点,牌抽象为边,则问题转化为:
对于一张有向图,将某些边翻转,使得每个点的入度小于等于1。
先连边,我们发现整张图最多有2N个点,却只有N条边。这代表图的连通性极差,图被分成许多联通块,然后我们对于每个联通块进行分类讨论。
设连通块的边数为e,点数为v。
若e<v,则整张图一定无解,根据抽屉原理,至少有一个点的入度大于1;
若e=v,则该图是一颗基环树,环上的点入度不能为0,因为环上的点一定会被另一个环上的点指向,要使条件成立,则一定是一颗基还外向树;
若e=v+1,则该图是一棵树,可以先后进行两次dfs,求出所需要的最小花费。
第一次任选一点进行dfs,由儿子向父亲更新,若通过一条反边,则在f数组上加1,若dfs的是一颗基环树,则还需要记录未经过的一条边,防止第二次dfs的路径与第一次不同。然后进行第二次,由父亲向儿子更新,若通过反边,则在g数组上加1,反之减1。g数组与f数组在搜索树的根处相等。
在进行第二次dfs时,将每个节点的g值压进一个vector里面,然后sort一下,第一个便是最小值,与最小值相同的数的个数便是方案数。
最后相乘即可。
单次复杂度O(NlogN)
Code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<vector> 5 #include<algorithm> 6 #define LL long long 7 using namespace std; 8 const int N=100010; 9 const LL mod=998244353; 10 int t,n,m=1,mv=0,me=0,cnt=0,tot=0,top=0,start,endd,bridge; 11 int fi[N<<1],g[N<<1],f[N<<1]; 12 bool v[N<<1],vis[N<<1]; 13 struct edge{ 14 int u,v,ne; 15 }e[N<<1]; 16 vector<int> gg; 17 void add(int x,int y) 18 { 19 e[++m].u=x; 20 e[m].v=y; 21 e[m].ne=fi[x]; 22 fi[x]=m; 23 } 24 int read() 25 { 26 int s=0; 27 char c=getchar(); 28 while(c<‘0‘||c>‘9‘) c=getchar(); 29 while(c>=‘0‘&&c<=‘9‘){ 30 s=(s<<3)+(s<<1)+c-‘0‘; 31 c=getchar(); 32 } 33 return s; 34 } 35 void clean() 36 { 37 memset(fi,0,sizeof(fi)); 38 memset(e,0,sizeof(e)); 39 memset(f,0,sizeof(f)); 40 memset(g,0,sizeof(g)); 41 memset(v,false,sizeof(v)); 42 memset(vis,false,sizeof(vis)); 43 m=1;top=tot=cnt=0; 44 } 45 void dfs(int x) 46 { 47 v[x]=true;mv++; 48 for(int i=fi[x];i!=0;i=e[i].ne){ 49 int y=e[i].v; 50 me++; 51 if(v[y]) continue; 52 dfs(y); 53 } 54 } 55 void dfs1(int x,int p) 56 { 57 vis[x]=true; 58 for(int i=fi[x];i!=0;i=e[i].ne){ 59 int y=e[i].v; 60 if(y==p) continue; 61 if(vis[y]){ 62 start=x;endd=y;bridge=i; 63 } 64 else{ 65 dfs1(y,x); 66 f[x]+=f[y]+(i&1); 67 } 68 } 69 } 70 void dfs2(int x,int p) 71 { 72 gg.push_back(g[x]); 73 for(int i=fi[x];i!=0;i=e[i].ne){ 74 int y=e[i].v; 75 if(y==p||i==bridge||i==(bridge^1)) continue; 76 g[y]=g[x]+((i&1)==1?-1:1); 77 dfs2(y,x); 78 } 79 } 80 int main() 81 { 82 t=read(); 83 while(t--) 84 { 85 clean(); 86 n=read(); 87 for(int i=1;i<=n;i++){ 88 int x=read(),y=read(); 89 add(y,x);add(x,y); 90 } 91 int flag=0; 92 for(int i=1;i<=2*n;i++){ 93 if(!v[i]){ 94 mv=me=0; 95 dfs(i); 96 if(me/2>mv){ 97 printf("-1 -1\n"); 98 flag=1;break; 99 } 100 } 101 } 102 if(flag==1) continue; 103 int ans1=0;LL ans2=1; 104 for(int i=1;i<=2*n;i++){ 105 if(!vis[i]){ 106 LL num=0;start=endd=bridge=0; 107 gg.clear(); 108 dfs1(i,0); 109 g[i]=f[i]; 110 dfs2(i,0); 111 if(bridge==0){ 112 sort(gg.begin(),gg.end()); 113 ans1+=gg[0]; 114 for(int j=0;j<gg.size();j++){ 115 if(gg[j]!=gg[0]) break; 116 num++; 117 } 118 } 119 else{ 120 bridge&=1; 121 if(g[start]+(bridge^1)==g[endd]+bridge) num=2; 122 else num=1; 123 ans1+=min(g[start]+(bridge^1),g[endd]+bridge); 124 } 125 ans2=ans2*num%mod; 126 } 127 } 128 printf("%d %lld\n",ans1,ans2); 129 } 130 return 0; 131 }
标签:mes 次数 get getchar 一点 etc als ns2 tar
原文地址:https://www.cnblogs.com/hz-Rockstar/p/11227914.html