您的位置:首页 > 大数据 > 人工智能

hdu-5318 The Goddess Of The Moon(2015 Multi-University Training Contest 3)

2015-08-03 23:48 429 查看
首先放一个矩阵快速幂的模板。

#include<vector>

typedef vector<long long> vec;
typedef vector<vec> mat;
typedef long long ll;
const int M = 1000000007;

mat mul(mat &A,mat &B)
{
mat C(A.size(), vec(B[0].size()));
for (int i = 0; i < A.size(); i++)
for (int k = 0; k < B.size(); k++)
for (int j = 0; j < B[0].size(); j++)
C[i][j] = (C[i][j] + A[i][k] * B[k][j]) %M;
return C;
}

mat pow(mat A, ll n){
mat B(A.size(), vec(A.size()));
for (int i = 0; i < A.size(); i++){
B[i][i] = 1;
}
while (n > 0){
if (n & 1) B = mul(B,A);
A = mul(A,A);
n >>= 1;
}
return B;
}
void solve(int n,int m)
{
mat a(n,vec(n));//n是行数,n也是列数
for (int i = 0;i < n; i++){
for (int j = 0; j < n; j++){
if (check(luf[i],luf[j])) a[i][j] = 1;
else a[i][j] = 0;
}
}
a = pow(a,m);
printf("%I64d\n",a[0][0]);
}


set可以用于去重。

以下包括了set的插入,set的查找,set的遍历。

<span style="white-space:pre">	</span>#include<set>
set<int> st;
st.clear();
for (int i = 0; i < n; i++){
int tmp;
scanf("%d",&tmp);
if (st.find(tmp) == st.end()){
//上面这句判断去掉也没关系。亲测可行。但是顺便写一下set查找用法嘛~map查找也是一样
st.insert(tmp);
}
}

//遍历st集合
set<int>::reverse_iterator rit;
for(rit=st.rbegin();rit!=st.rend();rit++){
printf("%d   ",*rit);
}
printf("set = %d\n",realn);


接下来是string和char[]的互相转换、把数字转换成char[]、string 子串的比较。

//printf打印string类的方法。不推荐。
string s = "aaa";
printf("%s", s.c_str());

//char[] 转成 string
char ch[10] = "qwe";
string pp = ch;

//string 转成 char []
string pp = "asdf";
char p[8];
int i;
for( i=0;i<pp.length();i++)
p[i] = pp[i];
p[i] = '\0';
printf("%s",p);

//把set中的string复制到char中的方法
char ch[SIZE_N][SIZE_N];
set<string> st;
int tn = 0;
for(auto &it:st) strcpy(ch[++tn], it.c_str());
n = tn;

//把数字转换成字符串的方法
char s1[20],s2[20];
sprintf(s1,"%d",a);
sprintf(s2,"%d",b);
int len1=strlen(s1),len2=strlen(s2);

//字符串的比较。
//方法一:
if(string(s1+i,s1+len1)==string(s2,s2+j+1))//相当于[s1[i],s1[len1-1] ] 和 [s2[0],s2[j] ] 这两个比较
//方法2:
string a,b;
string ta,tb;
for(i=0; i<la; i++) {
ta=a.substr(i);
for(j=0; j<=lb; j++) {
tb=b.substr(0,j);
if(ta==tb && (int)ta.length()>1) return 1;
}
}


题意:给你很多个数字串。如果A串的后缀正好是B串的前缀(前缀大于等于2),那么A就可以和B串连在一起。问你如果想要变成一条一共m个串的链,有几种方案。

比如:

m=2

123    234

那么就有123自己接自己一种,234 自己接自己一种,123接234一种。共三种方式。

题解:

1、首先。要考虑自己可以接自己啊!!!那么就算你给你三个数字接成一个环也有炒鸡多种接法。

2、画成图。就会发现是从A点到B点,途中经过m个点有几种方案数的问题。(据说这是经典的矩阵快速幂问题,我真是孤陋寡闻)

3、列dp方程式。dp[i][j]方程中i代表选择了i个串,j代表结尾是j

dp[i][j] = 求和dp[i-1][k].并且k和j可以相连

构造a矩阵,ij相连这个地方就是1.

example:dp[i][3] = dp[i-1][1] * a[1][3] + dp[i-1][2] * a[2][3] + dp[i-1][3] * a[3][3];

构造矩阵之后每次就把数字求出来就可以了

用矩阵快速幂。构造矩阵a之后求m - 1  次幂出来即可。

4、然后具体这个矩阵a是怎么推导出来的。

现在想象有一个3*3的矩阵A,A[i][j] 的数字为1表示i到j有路可以走。那么A^2就表示i走两步到达j有几种方法,A^3就表示i走三步到j有几种方法。A^(m-1)中的每一个A[i][j]表示i到j经过m-2个点,也就是包括首尾经过一共m个点。整个A^(m-1)的所有的元素求和求一遍,就是最后的答案啦~

注意点:

1、矩阵快速幂的时候记得把这个矩阵弄成long long,否则算的时候会溢出的~

2、这道题的一个坑点就是输入的串可能会重复。以下是预防重复的三种方法。

清除重复串和数字转字符串的方法
//清除重复串的方法1:用数组和unique
int use[SIZE_N];
for(i=0;i<N;i++)
scanf("%d",&use[i]);
sort(use,use+N);
N=unique(use,use+N)-use//此时的use是已经无重复串的一个数组啦

//清除重复串的方法2:用set和另一个乱七八糟的东西
set <string> st;
for(int i = 1;i <= n; i++) {
scanf("%s", ch[i]);
st.insert(ch[i]);
}
int tn = 0;
for(auto &it:st) strcpy(ch[++tn], it.c_str());
n = tn;

//清除重复串的方法3:用map
map<string,int> mp;
for(i=0; i<n; i++) {
cin>>ss;
if(mp.find(ss)==mp.end()) {
mp[ss]=k++;
str[cnt++]=ss;
}
}
N=cnt;

——————————我是预防傻逼博客它贴了代码后再按回车另一起一行就不能写文字而变成代码的分割线——————————————

那么我用了哪种方法呢?那就是三种都没用~哈哈哈哈就是这么可爱哈哈哈哈

以下是本题代码。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#define SIZE_N 330
using namespace std;

typedef vector<long long> vec;
typedef vector<vec> mat;
typedef long long ll;

int luf[SIZE_N];
int realn;

int a[SIZE_N][SIZE_N];

bool check(int a,int b) //ok
{
char s1[20],s2[20];
sprintf(s1,"%d",a);
sprintf(s2,"%d",b);
int len1=strlen(s1),len2=strlen(s2);
for(int i=len1-1,j=0;i>=0 && j<len2;i--,j++)
if(len1-i>=2 && string(s1+i,s1+len1)==string(s2,s2+j+1))
return true;
return false;
}

int checkori(int a,int b)
{
//printf("\na = %d b = %d\n",a,b);
if (a <10 || b < 10) return 0;
char s1[20],s2[20];
sprintf(s1,"%d",a);
sprintf(s2,"%d",b);
int len1=strlen(s1),len2=strlen(s2);//表示每个串的非终结符部分一共几位
//printf("a = %d b = %d %d %d",a,b,len1,len2);
for (int i = len1-2; i >= 0; i--){
int j = len1- i;
if (string(s1 + i, s1 + len1) == string(s2,s2+j)){
//printf("a = %d b = %d\n",a,b);
return 1;
}
}
return 0;
}

const int M = 1000000007;

mat mul(mat &A,mat &B)
{
mat C(A.size(), vec(B[0].size()));
for (int i = 0; i < A.size(); i++)
for (int k = 0; k < B.size(); k++)
for (int j = 0; j < B[0].size(); j++)
C[i][j] = (C[i][j] + A[i][k] * B[k][j]) %M;
return C;
}

mat pow(mat A, ll n){
mat B(A.size(), vec(A.size()));
for (int i = 0; i < A.size(); i++){
B[i][i] = 1;
}
while (n > 0){
if (n & 1) B = mul(B,A);
A = mul(A,A);
n >>= 1;
}
return B;
}
void solve(int n,int m)
{
mat a(n,vec(n));
for (int i = 0;i < realn; i++){
//printf("%d ",luf[i]);
for (int j = 0; j < realn; j++){
if (check(luf[i],luf[j])) a[i][j] = 1;
else a[i][j] = 0;
}
}
//记得把a矩阵也换成 long long

a = pow(a,m-1);
long long res = 0;
for (int i = 0; i < realn; i++)

for (int j = 0; j < realn; j++)
res = (res + a[i][j]) %M;

//res = (res + a[0][i]) % M;
printf("%I64d\n",res);
}

set<int> st;
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
#endif
int T,n,m;
scanf("%d",&T);
while (T--){
scanf("%d %d",&n,&m);
realn = 0;
for (int i = 0; i < n; i++){
scanf("%d",&luf[i]);
}
sort(luf,luf+n);
realn=unique(luf,luf+n)-luf;//此时的use是已经无重复串的一个数组啦
solve(realn, m);
}
return 0;
}

————————END————————
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息