【2019.1.26】动规专题测试
T1 公交车换乘
- 【题目描述】
假设某条街上每一公里就有一个公共汽车站,并且乘车费用如下表:
公里数 1 2 3 4 5 6 7 8 9 10
费用 12 21 31 40 49 58 69 79 90 101
而任意一辆汽车从不行驶超过10公里。某人想恰好行驶n公里,假设他可以任意次换车,请你帮他找到一种乘车方案,使得总费用最小。
注意:10公里的费用比1公里小的情况是允许的。
- 【输入】
输入共两行,第一行为10个不超过200的整数,依次表示行驶1~10公里的费用,相邻两数间用一个空格隔开;第二行为某人想要行驶的公里数。
- 【输出】
输出仅一行,包含一个整数,表示行使这么远所需要的最小费用。
- 【输入样例】
12 21 31 40 49 58 69 79 90 101
15
- 【输出样例】
147
- 【数据规模】
100%的数据满足:输入中所有数均为正整数,且不超过200
我能说我没读懂题意然后揣摩题揣摩了很久,然后对着样例尝试dou出147吗 我该滚回去学常规了 然后时间到,一解释,五分钟搞完
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 id:gww 3 language: 4 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 5 */ 6 #include<bits/stdc++.h> 7 using namespace std; 8 const int N=100+20; 9 const int M=500+20; 10 const int inf=0x3f3f3f3f; 11 int k[15],f[205],n; 12 int rd() 13 { 14 int x=0,w=0;char ch=0; 15 while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} 16 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 17 return w?-x:x; 18 } 19 20 int main() 21 { 22 memset(f,inf,sizeof(f)); 23 for(int i=1;i<=10;i++) 24 {k[i]=rd();f[i]=k[i];} 25 n=rd(); 26 for(int i=1;i<=n;i++) 27 for(int j=1;j<=10;j++) 28 f[i+j]=min(f[i+j],f[i]+k[j]); 29 printf("%d",f[n]); 30 return 0; 31 }
T2 数字矩阵
- 【题目描述】
给一个由数字组成的矩形,每次可以向左、向右、向下走,求一条从最上层的任意一个点走到最下层的任意一个点最小数字和的路径,输出其值。
- 【输入】
输入第一行包含两个数n, m,表示矩形的行数和列数。
接下来的n行每行有m个数,每个数表示矩形该位置上的值。
- 【输出】
输出最上层的任意一个点走到最下层的任意一个点的最小数字和的路径值。
- 【输出样例】
3 4
9 9 1 9
2 2 2 9
1 9 9 9
- 【输出样例】
8
- 【样例解释】
9 9 1 9
2 2 2 9
1 9 9 9 是最优方案
向左向右各跑一遍 开始只跑了一遍然后又去写暴力炸了 就放弃了自我
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 id:gww 3 language: 4 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 5 */ 6 #include<bits/stdc++.h> 7 using namespace std; 8 const int N=100+20; 9 const int M=500+20; 10 const int inf=0x3f3f3f3f; 11 int n,m,mp[N][M],f[N][M],ans=inf; 12 bool vis[N][M]; 13 int rd() 14 { 15 int x=0,w=0;char ch=0; 16 while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} 17 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 18 return w?-x:x; 19 } 20 21 int main() 22 { 23 memset(f,inf,sizeof(f)); 24 n=rd(),m=rd(); 25 for(int i=1;i<=n;i++) 26 for(int j=1;j<=m;j++) 27 mp[i][j]=rd(); 28 for(int i=1;i<=m;i++) 29 f[1][i]=mp[1][i]; 30 for(int i=2;i<=n;i++) 31 { 32 for(int j=1;j<=m;j++)//向下走 向右 33 f[i][j]=min(f[i][j],min(f[i-1][j],f[i][j-1])+mp[i][j]); 34 for(int j=m;j>=1;j--)//向左 35 f[i][j]=min(f[i][j],f[i][j+1]+mp[i][j]); 36 } 37 for(int i=1;i<=m;i++) 38 ans=min(ans,f[n][i]); 39 printf("%d",ans); 40 return 0; 41 }
T3 排列
- 【题目描述】
给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0)。例如123434有90种排列能被2整除,其中末位为2的有30种,末位为4的有60种。
- 【输入】
输入第一行是一个整数T,表示测试数据的个数,以下每行一组s和d,中间用空格隔开。s保证只包含数字0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
- 【输出】
每个数据仅一行,表示能被d整除的排列的个数。
- 【输入样例】
7
000 1
001 1
1234567890 1
123434 2
1234 7
12345 17
12345678 29
- 【输出样例】
1
3
3628800
90
3
6
1398我写的时候忘了unique是怎么用的,排序后直接让ans=unique(a+1,a+1+n) 应该是ans=unique(a+1,a+1+n)-a 然后就一直报错QAQ硬刚好久
- 关于next_permutation
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 id:gww 3 language: 4 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 5 */ 6 #include<bits/stdc++.h> 7 using namespace std; 8 int rd() 9 { 10 int x=0,w=0;char ch=0; 11 while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} 12 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 13 return w?-x:x; 14 } 15 int main() 16 { 17 int a[]={5,4,9}; 18 sort(a,a+3); 19 do 20 { 21 for(int i=0;i<=2;i++) 22 printf("%d ",a[i]); 23 printf("\n"); 24 }while(next_permutation(a,a+3)); 25 return 0; 26 }
f[s][k]表示已选取集合s中的数字%d的余数为k的情况数
然后就是去重操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 id:gww 3 language: 4 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 5 */ 6 #include<bits/stdc++.h> 7 using namespace std; 8 const int N=15; 9 const int inf=0x3f3f3f3f; 10 char s[N]; 11 int mo,a[N],f[1<<N][1000+5]; 12 int rd() 13 { 14 int x=0,w=0;char ch=0; 15 while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} 16 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 17 return w?-x:x; 18 } 19 20 21 int main() 22 { 23 int t=rd(); 24 25 while(t--) 26 { 27 memset(f,0,sizeof(f)); 28 f[0][0]=1; 29 scanf("%s",s);mo=rd(); 30 int ls=strlen(s); 31 for(int i=0;i<ls;i++) 32 if(s[i]>='0'&&s[i]<='9') 33 a[i+1]=s[i]-'0'; 34 for(int st=0;st<(1<<ls);st++)//枚举状态 35 for(int k=0;k<=mo;k++)//枚举余数 36 { 37 if(f[st][k]) 38 { 39 for(int i=1;i<=ls;i++)//枚举数 40 if((st&(1<<(i-1)))==0)//如果没有放入 41 f[st|(1<<(i-1))][(k*10+a[i])%mo]+=f[st][k]; 42 } 43 } 44 int ans=f[(1<<ls)-1][0]; 45 for(int i=0;i<=9;i++)//去重 46 { 47 int cnt=0; 48 for(int j=1;j<=ls;j++) 49 if(a[j]==i) cnt++; 50 int r=1; 51 for(int k=1;k<=cnt;k++) 52 r*=k; 53 ans/=r; 54 } 55 printf("%d\n",ans); 56 } 57 return 0; 58 }
[SCOI2007]排列 原题可以用暴力过QAQ
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 long long n,m,i,j,k,hrb[15],s=0,t; 4 char lxy[15]; 5 int main() 6 { 7 scanf("%lld",&t); 8 while(t) 9 { 10 scanf("%s%lld",lxy,&n); 11 m=strlen(lxy); 12 for(i=0;i<m;i++) 13 hrb[i+1]=lxy[i]-'0';//字符转数字 14 sort(hrb+1,hrb+m+1); 15 /*要排序,因为要递增序列,其实如果你够优秀(闲),你可以用next_permutation和prev_permutation各求一次,在把结果加起来*/ 16 s=0;//记得清0 17 do 18 { 19 long long ss=0; 20 for(i=1;i<=m;i++) 21 ss=ss*10+hrb[i];//求总值,因为函数也会修改数组 22 if(ss%n==0)s++; 23 } 24 while(next_permutation(hrb+1,hrb+m+1)); 25 //当排列没有后(即变为了递减数列)返回0,就可以结束循环 26 printf("%lld\n",s);//输出答案 27 t--; 28 } 29 return 0; 30 }
总结
- QAQ我还是太菜了