2015 Multi-University Training Contest 8

来源:互联网 发布:vb.net教程 编辑:程序博客网 时间:2024/04/30 10:06

官方题解:2015 Multi-University Training Contest 8 solutions BY 绍兴一中




1005 Danganronpa

HDU 5384:http://acm.hdu.edu.cn/showproblem.php?pid=5384

题意:给n个字符串\(A_i\),m个字符串\(B_j\),定义\(f(A,B)\)为B字符串在A字符串中出现的次数,可以重叠。求对于每个\(A_i\),\(\sum_{j=1}^{m}f(A_i,B_j)\)的值



AC自动机。


用所有\(B_j\)字符串构造一个AC自动机

对于每个\(A_i\)扫描一次即可求出答案


#include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<cstring>#include<queue>#include<vector>#include<string>#include<map>using namespace std;#define pb push_back#define LL __int64#define N 100005#define INF 1<<30struct node {    node *fail;    node *next[26];    int count;    node() {        fail=NULL;        count=0;        for(int i=0; i<26; ++i) {            next[i]=NULL;        }    }};node *root;queue<node*> q;void insert(string str) {    int k,len;    int i;    node *p=root;    len=str.size();    for(i=0; i<len; ++i) {        k=str[i]-'a';        if(p->next[k]==NULL)            p->next[k]=new node();        p=p->next[k];    }    p->count++;}void build_ac() {   //初始化fail指针,BFS    node *now,*nex;    int i,j;    while(!q.empty())q.pop();    q.push(root);    while(!q.empty()) {        now=q.front();        q.pop();        nex=NULL;        for(i=0; i<26; ++i) {            if(now->next[i]!=NULL) {                if(now==root) {         //第一个元素fail必指向根                    now->next[i]->fail=root;                } else {                    nex=now->fail;        //失败指针                    while(nex!=NULL) {      //2种情况结束:匹配为空or找到匹配                        if(nex->next[i]!=NULL) {     //找到匹配                            now->next[i]->fail=nex->next[i];                            break;                        }                        nex=nex->fail;                    }                    if(nex==NULL)   //为空则从头匹配                        now->next[i]->fail=root;                }                q.push(now->next[i]);            }        }    }}int query(string txt) {    int k,len,res;    node *p=root;    res=0;    len=txt.size();    for(int i=0; i<len; ++i) {        k=txt[i]-'a';        while(p->next[k]==NULL&&p!=root)  //跳转失败指针            p=p->fail;        p=p->next[k];        if(p==NULL)            p=root;        node *temp=p;   //p不动,temp计算后缀串        while(temp!=root) { //&&temp->count!=-1){            res+=temp->count;            //temp->count=-1;//重复不再计算            temp=temp->fail;        }    }    return res;}string a[N],b;int main() {    //freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);    //freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);    //std::ios::sync_with_stdio(false);    int n,m;    int T;    cin>>T;    while(T--) {        root=new node();        cin>>n>>m;        for(int i=1; i<=n; ++i)            cin>>a[i];        for(int i=1; i<=m; ++i) {            cin>>b;            insert(b);        }        build_ac();        for(int i=1; i<=n; ++i)            printf("%d\n",query(a[i]));    }    return 0;}


1007 Cover

HDU 5386:http://acm.hdu.edu.cn/showproblem.php?pid=5386

题意:有一个n*m的矩阵,定义两种操作:

L x y: for(int i=1;i<=n;i++)color[i][x]=y;
H x y:for(int i=1;i<=n;i++)color[x][i]=y;

现在给出矩阵的初始状态和终态,以及m个操作,求能满足条件的操作顺序


我们只要每次找一行或一列颜色除了00都相同的,然后如果有对应的操作,就把这行这列都赋值成00即可

答案只与终态有关。


#include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<cstring>#include<queue>#include<vector>#include<string>#include<map>using namespace std;#define pb push_back#define LL __int64#define N 505#define INF 1<<30int dir[N],x[N],y[N];int mpt[N][N];int vis[N];int ans[N];int n,m;int cle=0;int judge(int d,int opx,int opy) {    for(int i=1; i<=m; ++i)        if(!vis[i]&&((dir[i]==d&&x[i]==opx&&(y[i]==opy||opy==0))||cle)) {            vis[i]=1;            return i;        }    return 0;}void change(int id) {    if(dir[id]==1)        for(int i=1; i<=n; i++)mpt[i][x[id]]=0;    if(dir[id]==2)        for(int i=1; i<=n; i++)mpt[x[id]][i]=0;}int main() {    //freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);    //freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);    int T;    scanf("%d",&T);    while(T--) {        cle=0;        memset(vis,0,sizeof(vis));        scanf("%d%d",&n,&m);        for(int i=1; i<=n; ++i)            for(int j=1; j<=n; ++j)                scanf("%d",&mpt[i][j]);        for(int i=1; i<=n; ++i)            for(int j=1; j<=n; ++j)                scanf("%d",&mpt[i][j]);        char op[2];        for(int i=1; i<=m; ++i) {            scanf("%s%d%d",op,&x[i],&y[i]);            if(op[0]=='L')dir[i]=1;            else dir[i]=2;        }        int k=m;        int opy;        int id;        while(k) {            int flag=0;            id=0;            for(int i=1; i<=n&&!flag; ++i) {                int same=1;                opy=mpt[1][i];                for(int j=2; j<=n&&same; ++j) {                    if(mpt[j][i]!=opy&&mpt[j][i]!=0&&opy!=0) same=0;                    opy=max(opy,mpt[j][i]);                }                if(same) {                    id=judge(1,i,opy);                    flag=(id?1:0);                }            }            for(int i=1; i<=n&&!flag; ++i) {                int same=1;                opy=mpt[i][1];                for(int j=2; j<=n&&same; ++j) {                    if(mpt[i][j]!=opy&&mpt[i][j]!=0&&opy!=0) same=0;                    opy=max(opy,mpt[i][j]);                }                if(same) {                    id=judge(2,i,opy);                    flag=(id?1:0);                }            }            ans[k--]=id;            change(id);            flag=1;            for(int i=1; i<=n&&flag; ++i)                for(int j=1; j<=n&&flag; ++j)                    if(mpt[i][j]!=0)flag=0;            if(flag)cle=1;        }        for(int i=1; i<=m; ++i) {            if(i!=1)printf(" ");            printf("%d",ans[i]);        }        printf("\n");    }    return 0;}


1008 Clock

HDU 5387:http://acm.hdu.edu.cn/showproblem.php?pid=5387

题意:给一个时刻,分别求时针与分针,时针与秒针,分针与秒针的角度


计算一下角度就行,注意分数以及钝角的处理


#include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<cstring>#include<queue>#include<vector>#include<string>#include<map>using namespace std;#define pb push_back#define LL __int64#define N 100005#define INF 1<<30int gcd(int a,int b) {    return (b>0)?gcd(b,a%b):a;}int main() {    //freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);    //freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);    int ans[4];    int T;    int h,m,s;    int hh,mm,ss;    scanf("%d",&T);    while(T--) {        scanf("%d:%d:%d",&h,&m,&s);        if(h>=12)h-=12;        hh=h*30*3600+m*30*60+s*30;        mm=m*6*3600+s*6*60;        ss=s*6*3600;        ans[1]=abs(hh-mm);        ans[2]=abs(hh-ss);        ans[3]=abs(mm-ss);        for(int i=1; i<=3; ++i) {            ans[i]=min(360*3600-ans[i],ans[i]);            if(ans[i]%3600==0)                printf("%d",ans[i]/3600);            else {                printf("%d/%d",ans[i]/gcd(ans[i],3600),3600/gcd(ans[i],3600));            }            printf(" ");        }        printf("\n");    }    return 0;}


1010 Zero Escape

HDU 5389:http://acm.hdu.edu.cn/showproblem.php?pid=5389

题意:n个人,每人有一个标识符\(id_i\)(可以相同),现有两道门编号为\(A,B\)(可以相同)。对每个人要选择一个门通过。最后选择同一个门的人的标识符之和的数根和门的编号相同就可以通过。求能让所有人通过的方案数。


DP


定义\(dr(x)\)为\(x\)的数根

数根有一个性质:\(dr(a+b) \equiv dr(a)+dr(b)\space (\mod 9\space )\)

所以可以用\(dp[i][j]\)表示从前\(i\)个数中选出一些数使其和的树根对9取模为\(j\)的方案数有多少

状态转移方程:

\(for \ each \  j \in [0,9]\)

\(\qquad dp[i][j]=dp[i-1][j]\)
\(\qquad dp[i][(j+d[i]) \% 9]=dp[i][(j+d[i]) \% 9]+dp[i-1][j]\)


#include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<cstring>#include<queue>#include<vector>#include<string>#include<map>using namespace std;#define pb push_back#define LL __int64#define N 100005#define INF 1<<30#define MOD 258280327int n;int d[N];LL dp[N][10];int sum;int A,B;int main(){    //freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);    //freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);    int T;    scanf("%d",&T);    while(T--){        sum=0;        memset(dp,0,sizeof(dp));        scanf("%d%d%d",&n,&A,&B);        for(int i=1;i<=n;++i){            scanf("%d",&d[i]);            sum+=d[i];        }        sum%=9;        dp[1][d[1]]=1;        dp[1][0]=1;        for(int i=2;i<=n;++i){            for(int j=0;j<=9;++j){                dp[i][j]=(dp[i][j]+dp[i-1][j])%MOD;                dp[i][(j+d[i])%9]=(dp[i][(j+d[i])%9]+dp[i-1][j])%MOD;            }        }        LL ans=0;        if((A+B)%9==sum)ans=dp[n][A%9];        if(ans==0&&(sum%9==A%9||sum%9==B%9))ans++;        printf("%I64d\n",ans%MOD);    }    return 0;}



0 0
原创粉丝点击