2019 ccpc 秦皇岛 部分题解(F(找环),I(dp),J(KMP求循环串))

F题

求方案数 使得去掉一些边使得最初始的图变成森林。。。通过观察样例可已得知,当存在一个环,那么答案的贡献就是这个环的边数num:2^num-1.。其他的边是可以去掉,也可以不去掉,那么就是乘2.。。

当不存在环则答案需要减一,因为必须得去掉一些边。。

求环可以用dfs加时间戳写,也可以用tarjan求点双连通分量求。。。。

#include
#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
#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

I-Invoker

这种题不是傻逼题吗?重现赛,我当时dp状态也想出来了,转移方程也想对了,不知道是状态不好还是什么原因,可能是单挑有点弱,不太想打代码,随便打了两下。。晚上花了半个小时就写出来。。。有点无语,操!!!!。。。

#include
#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
#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
*/

 

J-MUV LUV EXTRA

要求后缀必须为循环串得一部分。。

求小数点后一段字符串的长度*a-这个字符串的循环节的长度*b,输出最大值。

其实kmp找循环串得专题我做了好几个,不过 过了很久,有点忘记了。。。之前有点误解这个题得题意了,导致想歪了。。

#include
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

 

你可能感兴趣的:(网络赛题解)