CODE FESTIVAL 2017 qual C

来源:互联网 发布:前10月经济数据 编辑:程序博客网 时间:2024/05/29 06:38

A
枚举

B
dp

C
因为可以添加x,所以我们可以忽略原串中的x,若剩下的串不回文则不合法,否则可以知道最终的回文串的中心是哪个字符,从两边向中间枚举非x的字符,添加x使他们的位置对应

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;const int maxn = 410000;int n,m;char str[maxn];char s[maxn];int pos[maxn];int main(){    scanf("%s",str); n=strlen(str);    m=0; for(int i=0;i<n;i++) if(str[i]!='x') pos[m]=i,s[m++]=str[i];    if(!m) return puts("0"),0;    for(int i=0;i<m;i++) if(s[i]!=s[m-i-1]) return puts("-1"),0;    int ans=0;    int lai=0,laj=n-1,j=m-1;    for(int i=0;i<=j;i++,j--)    {        int x=pos[i]-lai,y=laj-pos[j];        if(x!=y) ans+=abs(x-y);        lai=pos[i],laj=pos[j];    }    printf("%d\n",ans);    return 0;}

D
f[i]表示前i个字符,最少要分成多少段,f[j]能转移到f[i]只有当j+1~i里面每种字符至多只能有一种出现奇数次,令g[i]二进制下第k位表示1~i k字母出现次数的奇偶性,则g[j]=g[i]或者g[j]和g[i]二进制只有一位不同
写个哈希表维护相同g[j]的最小值,枚举第0~26位与g[i]不同的g[j]更新f[i]

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long long#define inf 1e9using namespace std;inline void down(int &x,const int &y){if(x>y)x=y;}const int maxn = 410000;const int mod = 2333333;int n;char str[maxn];int f[maxn];struct edge{int y,c,nex;}a[mod]; int len,fir[mod];inline void link(const int x,const int y,const int c){a[++len]=(edge){y,c,fir[x]};fir[x]=len;}void ins(const int x,const int ff){    int cc=x%mod;    for(int k=fir[cc],y=a[k].y;k;k=a[k].nex,y=a[k].y)    {        if(a[k].y==x) { down(a[k].c,ff); return; }    }    link(cc,x,ff);}int fi(const int x){    int cc=x%mod;    for(int k=fir[cc],y=a[k].y;k;k=a[k].nex)        if(a[k].y==x) return a[k].c;    return inf;}int main(){    scanf("%s",str+1); n=strlen(str+1);    f[0]=1; ins(0,0);    int now=0;    for(int i=1;i<=n;i++)    {        f[i]=inf;        now^=1<<str[i]-'a';        int mn=n+1;        for(int j=0;j<26;j++) down(mn,fi(now^1<<j));        down(mn,fi(now));        f[i]=mn+1;        ins(now,f[i]);    }    printf("%d\n",f[n]);    return 0;}

E
没看懂啊啊啊啊
所以不想做跳了..

F
发现我们只需要考虑C吃的寿司,对于A,B第i次吃的寿司,只要求在c中的位置在c第i次吃的寿司之后,这个对于所有C吃的寿司序列,系数都是一样的,可以求出C吃的序列数后再做个dp求出这个系数。
求合法的C吃的寿司序列数,dp时C吃的什么先不确定,记作?,f[i][j][k]表示A吃到序列的第i个位置,B吃到j,C有k个?
转移时,如果当前的i,j不合法,转移到i+1或j+1,注意a[i]=b[j]的情况要特判,此时A,B都吃到了a[i]这个数,C中的?一定有一个是a[i],否则A,B就会有fight,所以转移到i+1,j+1,k-1带系数k
若i,j合法,有4种情况,
(1:?中没有a[i]和b[j],转移到i+1,j+1,k+1,
(2:?中有a[i]即C之前已经吃了a[i],转移到i+1,j,k-1带系数k,
(3:?中有b[j],同理到i,j+1,k-1带系数k,
(4:?中同时有a[i]和b[j],这种情况会被2,3各算一次,所以这种情况会转移到i+1,j+1,k-2带系数-k*(k-1)(去重)
算出C的序列数后再dp g[i][j]表示前i个位置放了j个不是C吃的数

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long long#define __ %=Modusing namespace std;const int maxn = 405;const ll Mod = 1e9+7;int n,N;int a[maxn],b[maxn];ll f[maxn][maxn][200];int as[maxn],bs[maxn];ll g[maxn][maxn];int main(){    scanf("%d",&n); N=n/3;    for(int i=1;i<=n;i++) scanf("%d",&a[i]),as[a[i]]=i;    for(int i=1;i<=n;i++) scanf("%d",&b[i]),bs[b[i]]=i;    //if(a[1]==b[1]) return puts("0"),0;    f[1][1][0]=1ll;    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=0;k<=N;k++) if(f[i][j][k])    {        ll tmp=f[i][j][k];        if(bs[a[i]]<=j||as[b[j]]<=i)        {            if(a[i]==b[j])            {                if(k) (f[i+1][j+1][k-1]+=tmp*(ll)k%Mod)__;                continue;            }            if(bs[a[i]]<=j) (f[i+1][j][k]+=tmp)__;            else (f[i][j+1][k]+=tmp)__;            continue;        }        (f[i+1][j+1][k+1]+=tmp)__;        if(!k) continue;        (f[i+1][j][k-1]+=tmp*(ll)k%Mod)__;        (f[i][j+1][k-1]+=tmp*(ll)k%Mod)__;        (f[i+1][j+1][k-2]-=tmp*(ll)k%Mod*(k-1)%Mod)__;    }    ll re=0;    for(int i=N+1;i<=n+1;i++)        (re+=f[i][n+1][0]+f[n+1][i][0])__;    (re-=f[n+1][n+1][0]-Mod)%=Mod;    g[0][0]=1ll;    for(int i=0;i<n;i++) for(int j=0;j<=i;j++) if(g[i][j])    {        if(i-j<N) (g[i+1][j]+=g[i][j])__;        if(j<2*N&&(i-j)*2>j) (g[i+1][j+1]+=g[i][j]*(ll)((i-j)*2-j)%Mod)__;    }    (re*=g[n][2*N])__;    printf("%lld\n",re);    return 0;}
原创粉丝点击