F题(dfs判环)
链接:https://codeforces.com/gym/102361/problem/F
思路 如果环的边长为k,那么环的删边方案数是2k-1。如果链的边长为k,那么链的删边方案数是2k。环的方案数乘以链的方案数就是总的方案数
(之前没关同步wa了。。。)
代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int maxn=3e5+10;
const int mod=998244353;
#define ll long long
int n,m,cnt,tot;
ll ans;
vector<int>G[maxn];
int vis[maxn],deep[maxn];
ll power(ll a,ll b)
{
ll ans=1,x=a;
for(;b;b>>=1)
{
if(b&1)
{
ans=ans*x%mod;
}
x=x*x%mod;
}
return ans;
}
void dfs(int u,int fa)
{
deep[u]=deep[fa]+1;
for(int i=0;i<G[u].size();i++)
{
if(G[u][i]!=fa)
{
if(!vis[G[u][i]])
{
vis[G[u][i]]=1;
dfs(G[u][i],u);
}
else if(deep[G[u][i]]<deep[u])
{
int x=deep[u]-deep[G[u][i]]+1;
tot-=x;
ans=ans*(power(2,x)-1)%mod;
}
}
}
}
int main()
{
int u,v;
ios::sync_with_stdio(false);
cin>>n>>m;
ans=1,tot=m;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
vis[i]=1;
dfs(i,i);
}
}
ans=ans*power(2,tot)%mod;
cout<<ans<<"
";
return 0;
}
I 题(状态压缩dp)
链接:https://codeforces.com/gym/102361/problem/I
思路:暴力dp跑6种情况,每种情况都看前一个状态的6种情况,看这个状态与前面一个状态相同的字母与多少相同,复杂度O(36*n)
状态方程dp[i][k]=min(dp[i][k],dp[i-1][k]+solve(mn[s[i-1]],mn[s[i]],j,k)。i是当前状态,k表示6种情况的其中一种,j代表上一个状态下的6种情况,solve()函数表示这个状态与上一个状态的尾部与多少相同的字母。
代码
#include<bits/stdc++.h>
using namespace std;
char a[10][6][4]=
{
{{"QQQ"},{"QQQ"},{"QQQ"},{"QQQ"},{"QQQ"},{"QQQ"}},
{{"QQW"},{"QQW"},{"QWQ"},{"QWQ"},{"WQQ"},{"WQQ"}},
{{"QQE"},{"QQE"},{"EQQ"},{"EQQ"},{"QEQ"},{"QEQ"}},
{{"WWW"},{"WWW"},{"WWW"},{"WWW"},{"WWW"},{"WWW"}},
{{"WWQ"},{"WWQ"},{"WQW"},{"WQW"},{"QWW"},{"QWW"}},
{{"WWE"},{"WWE"},{"WEW"},{"WEW"},{"EWW"},{"EWW"}},
{{"EEE"},{"EEE"},{"EEE"},{"EEE"},{"EEE"},{"EEE"}},
{{"EEQ"},{"EEQ"},{"EQE"},{"EQE"},{"QEE"},{"QEE"}},
{{"WEE"},{"WEE"},{"EWE"},{"EWE"},{"EEW"},{"EEW"}},
{{"QWE"},{"QEW"},{"WEQ"},{"WQE"},{"EQW"},{"EWQ"}}
};
map<char,int>mn;
int dp[100010][6];
char s[100010];
int solve(int s,int t,int f,int g)
{
if(a[s][f][0]==a[t][g][0]&&a[s][f][1]==a[t][g][1]&&a[s][f][2]==a[t][g][2])
return 0;
else if(a[s][f][2]==a[t][g][1]&&a[s][f][1]==a[t][g][0])
return 1;
else if(a[s][f][2]==a[t][g][0])
return 2;
return 3;
}
int main()
{
scanf("%s",s);
mn['Y']=0,mn['V']=1,mn['G']=2,mn['C']=3,mn['X']=4,mn['Z']=5,mn['T']=6,mn['F']=7,mn['D']=8,mn['B']=9;
int ans=strlen(s);
memset(dp,0x3f3f3f,sizeof(dp));
for(int i=0;i<6;i++)
{
dp[0][i]=3;
}
for(int i=1;i<ans;i++)
{
for(int j=0;j<6;j++)
{
for(int k=0;k<6;k++)
{
dp[i][k]=min(dp[i][k],dp[i-1][j]+solve(mn[s[i-1]],mn[s[i]],j,k));
}
}
}
int res=2e9;
for(int i=0;i<6;i++)
{
res=min(res,dp[ans-1][i]);
}
res+=ans;
cout<<res<<"
";
return 0;
}