求方案数 使得去掉一些边使得最初始的图变成森林。。。通过观察样例可已得知,当存在一个环,那么答案的贡献就是这个环的边数num:2^num-1.。其他的边是可以去掉,也可以不去掉,那么就是乘2.。。
当不存在环则答案需要减一,因为必须得去掉一些边。。
求环可以用dfs加时间戳写,也可以用tarjan求点双连通分量求。。。。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=3e5+10,M=1e6+10;
const ll mod=998244353;
ll powmod(ll a,ll b) {ll res=1;a%=mod;
for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
int vs[N];
int n,m;
ll ans;
struct edge
{
int to,next;
}e[M];
int head[N],vis[M],cnt;
void add(int u,int v){
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt++;
e[cnt].to=u;
e[cnt].next=head[v];
head[v]=cnt++;
}
ll fm,fz;//±ßÊý,»·µÄ±ßÊý
void dfs(int u,int dep,int fa)
{
vs[u]=dep;
for(int i=head[u];i!=-1;i=e[i].next)
{
if(vis[i]) continue;
fm++;
vis[i]=vis[i^1]=1;
int v=e[i].to;
if(v==fa) continue;
if(vs[v]){
if(dep>vs[v])
{
fz+=dep-vs[v]+1;
ans=ans*(powmod(2,1ll*dep-vs[v]+1)-1)%mod;
}
continue;
}
dfs(v,dep+1,u);
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(head,-1,sizeof(head));
for(int i=1;i<=n;++i) vs[i]=0;
cnt=0;
for(int i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
ans=1;
fm=fz=0;
for(int i=1;i<=n;++i)
if(vs[i]==0) dfs(i,1,-1);
ans=(ans*powmod(2,fm-fz))%mod;
if(fz==0) printf("%lld\n",ans-1);
else printf("%lld\n",ans);
for(int i=0;i<cnt;++i) vis[i]=0;
}
}
这种题不是傻逼题吗?重现赛,我当时dp状态也想出来了,转移方程也想对了,不知道是状态不好还是什么原因,可能是单挑有点弱,不太想打代码,随便打了两下。。晚上花了半个小时就写出来。。。有点无语,操!!!!。。。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
//Q 10 W 100 E 1000
char tem[13][4]={"QQQ","QQW","EQQ","WWW","QWW","EWW","EEE","EEQ","EEW","EQW"};
int num[13]={30,120,1020,300,210,1200,3000,2010,2100,1110};
int getid(char c)
{
if(c=='B') return 9;
if(c=='Y') return 0;
if(c=='V') return 1;
if(c=='G') return 2;
if(c=='C') return 3;
if(c=='X') return 4;
if(c=='Z') return 5;
if(c=='T') return 6;
if(c=='F') return 7;
if(c=='D') return 8;
}
int f(int id)
{
if(id==1) return 10;
if(id==2) return 100;
if(id==3) return 1000;
}
const int N=1e5+10;
char s[N];
int dp[N][3][3][3];
int a[N];
const int inf=0x3f3f3f3f;
int main()
{
while(~scanf("%s",s+1)){
int n=strlen(s+1);
for(int i=1;i<=n;++i)
{
a[i]=num[getid(s[i])];
}
mem(dp,inf);
for(int j=1;j<=3;++j)
for(int k=1;k<=3;++k)
for(int p=1;p<=3;++p)
{
if(f(j)+f(k)+f(p)==a[1]){
//printf("j:%d k:%d p:%d\n",j,k,p);
dp[1][j][k][p]=3;
}
}
for(int i=2;i<=n;++i)
{
for(int j=1;j<=3;++j)
for(int k=1;k<=3;++k)
for(int p=1;p<=3;++p)
{
if(f(j)+f(k)+f(p)==a[i]){
dp[i][j][k][p]=dp[i-1][j][k][p];
}
}
for(int j=1;j<=3;++j)
for(int k=1;k<=3;++k)
for(int p=1;p<=3;++p)
for(int w=1;w<=3;++w)
{
if(f(k)+f(p)+f(w)==a[i])
{
dp[i][k][p][w]=min(dp[i][k][p][w],dp[i-1][j][k][p]+1);
}
}
for(int j=1;j<=3;++j)
for(int k=1;k<=3;++k)
for(int p=1;p<=3;++p)
for(int w=1;w<=3;++w)
for(int o=1;o<=3;++o)
{
if(f(p)+f(w)+f(o)==a[i]){
dp[i][p][w][o]=min(dp[i][p][w][o],dp[i-1][j][k][p]+2);
}
}
int t=inf;
for(int j=1;j<=3;++j)
for(int k=1;k<=3;++k)
for(int p=1;p<=3;++p) t=min(t,dp[i-1][j][k][p]);
//printf("t:%d\n",t);
for(int j=1;j<=3;++j)
for(int k=1;k<=3;++k)
for(int p=1;p<=3;++p) {
if(f(j)+f(k)+f(p)==a[i]){
dp[i][j][k][p]=min(t+3,dp[i][j][k][p]);
}
}
}
int ans=inf;
for(int i=1;i<=3;++i)
for(int j=1;j<=3;++j)
for(int k=1;k<=3;++k)
{
ans=min(ans,dp[n][i][j][k]);
//if(f(i)+(j)+f(k)==a[n])
}
printf("%d\n",ans+n);
}
}
/*
XDTBVV
*/
要求后缀必须为循环串得一部分。。
求小数点后一段字符串的长度*a-这个字符串的循环节的长度*b,输出最大值。
其实kmp找循环串得专题我做了好几个,不过 过了很久,有点忘记了。。。之前有点误解这个题得题意了,导致想歪了。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=1e18;
ll a,b;
int i,j,k;
const int N=1e7+10;
char s[N];
char s1[N];
int ne[N];
void getnext(char s[],int ne[])
{
int q,k;
int len=strlen(s);
ne[0] = 0;
for (q = 1,k = 0; q < len; ++q)
{
while(k > 0 && s[q] != s[k])
k = ne[k-1];
if (s[q] == s[k])
{
k++;
}
ne[q] = k;
}
}
int main()
{
while(~scanf("%lld%lld",&a,&b))
{
memset(ne,0,sizeof ne);
getchar();
gets(s1);
int len1=strlen(s1);
int len=0;
for(i=len1-1; i>=0; i--)
{
if(s1[i]=='.')
break;
s[len1-i-1]=s1[i];
len++;
}
getnext(s,ne);
ll ans=-INF;
for(i=0; i<len; i++)
{
ll res=a*(i+1)-b*(i+1-ne[i]);//i+1-ne[i]就是循环串的长度
ans=max(ans,res);
}
printf("%lld\n",ans);
}
return 0;
}