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个操作,求能满足条件的操作顺序
我们只要每次找一行或一列颜色除了0都相同的,然后如果有对应的操作,就把这行这列都赋值成0即可
答案只与终态有关。
#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;}
- 2015 Multi-University Training Contest 8
- 2015 Multi-University Training Contest 8
- 2015 Multi-University Training Contest 8(hdu5384,AC自动机)
- 2015 Multi-University Training Contest 8(HDOJ5384、5389)
- 2015 Multi-University Training Contest 8 The sum of gcd
- 2015 Multi-University Training Contest 1
- 2015 Multi-University Training Contest 1记录
- 2015 Multi-University Training Contest HDU5297
- 2015 Multi-University Training Contest 2
- 2015 Multi-University Training Contest 2
- 2015 Multi-University Training Contest 2
- 2015 Multi-University Training Contest 3
- 2015 Multi-University Training Contest 3
- 2015 Multi-University Training Contest 3 RGCDQ
- 2015 Multi-University Training Contest 4
- 2015 Multi-University Training Contest 4
- 2015 Multi-University Training Contest 4
- 2015 Multi-University Training Contest 4
- Yii2.0 游客访问限制
- Android:EditText 多行显示
- 使用Visual studio 各种版本 生成exe或者dll无法在其他机器运行的解决方式
- iOS UIView的setNeedsLayout, layoutIfNeeded 和 layoutSubviews 方法之间的关系解释
- 设计模式六大原则
- 2015 Multi-University Training Contest 8
- js data日期初始化的5种方法
- MySQL Study之--MySQL管理工具sqlyog
- LeetCode-Binary Tree Level Order Traversal
- JavaWeb项目目录结构
- ------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! ----
- Delphi打开外部程序或文件
- Leetcode -- Swap Nodes in Pairs
- 机房收费系统之神奇的“焦点”