题目:
在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。
要点总结:
最后一次合并也就是在最长的区间上面把两个分开的堆合并为一堆,那可以把前面每次合并看作一个区间上面选一个截断点,将这两部分合并。从2开始遍历区间长度,遍历该区间内所有起始坐标,然后遍历选择最优的间断点,每个间断点的合并代价为前面区间的最小合并代价加后面区间的最小合并代价以及区间里所有石头的数量,所有长度遍历完后1-n的代价即为最小的代价。动态规划的思想。
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<int> shizi(n+1);
vector<int> presum(n+1);
for(int i=1;i<=n;i++){
cin>>shizi[i];
presum[i]=presum[i-1]+shizi[i];
}
vector<vector<long long>> dp(n+1,vector<long long>(n+1,0));
for(int len=2;len<=n;len++){
for(int start=1;start<=n-len+1;start++){
int end=start+len-1;
dp[start][end]=LLONG_MAX;
for(int fenge=start;fenge<end;fenge++){
long long cost=dp[start][fenge]+dp[fenge+1][end]+(presum[end]-presum[start-1]);
if(cost<dp[start][end]) dp[start][end]=cost;
}
}
}
cout<<dp[1][n];
return 0;
}
题目:
有n个矩阵,大小分别为a0*a1, a1*a2, a2*a3, ..., a[n-1]*a[n],现要将它们依次相乘,只能使用结合率,求最少需要多少次运算。
两个大小分别为p*q和q*r的矩阵相乘时的运算次数计为p*q*r。
要点总结:
和前面题目一样思路,从小到大遍历所有的区间长度,在所有区间里面,遍历最优的间断点,乘法代价为间断点前的矩阵相乘的最小代价加上间断点之后矩阵相乘的最小代价加上前后俩矩阵相乘的代价。
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<long long> a(n+1);
for(int i=0;i<=n;i++){
cin>>a[i];
}
vector<vector<long long>> dp(n+1,vector<long long>(n+1,0));
for(int len=2;len<=n;len++){
for(int start=1;start<=n-len+1;start++){
int end=start+len-1;
dp[start][end]=LLONG_MAX;
for(int fenge=start;fenge<end;fenge++){
long long cost=dp[start][fenge]+dp[fenge+1][end]+a[start-1]*a[fenge]*a[end];
if(cost<dp[start][end]) dp[start][end]=cost;
}
}
}
cout<<dp[1][n];
return 0;
}
题目:
3000米长跑时,围观党们兴高采烈地预测着最后的排名。因为他们来自不同的班,对所有运动员不一定都了解,于是他们分别对自己了解的一些运动员的实力作出了评估,即对部分运动员做了相对排名的预测,并且告诉了可怜留守的班长。因为无聊,于是他们就组团去打Dota去了。比赛结束后他们向班长询问最后的排名,但班长不记得了,只记得他们中哪些人的预测是正确的,哪些人的预测是错误的。他们想知道比赛的排名可能是什么。
要点总结:
直接枚举所有可能的排名的排列组合,对于每个排名,遍历所有围观者的预测,正确的必须是排名的子集,不正确的必须不是子集,判断是否是子集的方法要记忆一下,记得判越界。
代码:
#include<bits/stdc++.h>
using namespace std;
struct weiguan{
vector<int> paimin;
int flag;
};
vector<vector<int>> res;
bool checkzi(vector<int> arr,vector<int> a){
int j=0;
for(int i=0;i<arr.size();i++){
if(j<a.size()&&arr[i]==a[j]){
j++;
}
}
return j==a.size();
}
int main(){
int n,m;
cin>>n>>m;
vector<int> arr(n);
for(int i=0;i<n;i++){
arr[i]=i;
}
vector<weiguan> aud;
for(int i=0;i<m;i++){
weiguan a;
int num;
cin>>num;
for(int j=0;j<num;j++){
int x;
cin>>x;
a.paimin.push_back(x);
}
cin>>num;
a.flag=num;
aud.push_back(a);
}
do{
bool valid=true;
for(weiguan a : aud){
if(a.flag==1){
if(!checkzi(arr,a.paimin)){
valid=false;
break;
}
}else{
if(checkzi(arr,a.paimin)){
valid=false;
break;
}
}
}
if(valid){
res.push_back(arr);
}
}while(next_permutation(arr.begin(),arr.end()));
cout<<res.size()<<endl;
for(vector<int> a : res){
for(int b : a){
cout<<b<<" ";
}
cout<<endl;
}
return 0;
}
题目:
有n(2≤n≤20)块芯片,有好有坏,已知好芯片比坏芯片多。
每个芯片都能用来测试其他芯片。用好芯片测试其他芯片时,能正确给出被测试芯片是好还是坏。而用坏芯片测试其他芯片时,会随机给出好或是坏的测试结果(即此结果与被测试芯片实际的好坏无关)。
给出所有芯片的测试结果,问哪些芯片是好芯片。
要点总结:
关键在于对题目的分析,因为好的都能被好的检测出来,而好的被不好的检测是一半一半的概率,所以直接遍历所有对该芯片检测的情况,只要其值大于一半,必然为好芯片。
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<vector<int>> arr(n+1,vector<int>(n+1));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>arr[i][j];
}
}
for(int i=1;i<=n;i++){
int sum=0;
for(int j=1;j<=n;j++){
sum+=arr[j][i];
}
if(sum>n/2){
cout<<i<<" ";
}
}
return 0;
}
题目:
给定三根杆A、B、C和大小不同的几个盘子。这些盘子按尺寸递减顺序套在A杆上,最小的在最上面。现在的任务是把这些盘子从A杆移到C杆且保持原来堆放顺序。在实现任务时,每次只能移动一个盘子,且任何时刻不允许大的盘子放在小的盘子上面,B杆可以作为辅助存放杆。求:总共有n个圆盘时,搬动过程中的第m步是从哪个杆到哪个杆。
要点总结:
汉诺塔问题分为三步,第一步把n-1个盘从A经由C移动到B,第二步把A最大的盘移动到C,第三步把n-1个盘从B经由A移动到C。第一步和第三步都需要2^(n-1)次的移动,所以总步数为2^n-1,如果超出总步数直接范围none,如果m在前面的2^(n-1)次,直接在移动n-1个盘里面找即可,并且是A经由C到B,如果在后面的2^(n-1)次,直接在移动后面的n-1个盘里找即可,如果正好是中间那一步,直接返回ori到tar。
代码:
#include<bits/stdc++.h>
using namespace std;
string findnum(int n,int m,char ori,char auxi,char tar){
int total=(1<<n)-1;
if(m>total) return "none";
if(n==1) return string("")+ori+"--"+tar;
int pre=(1<<(n-1))-1;
if(m<=pre) return findnum(n-1,m,ori,tar,auxi);
if(m==pre+1) return string("")+ori+"--"+tar;
else return findnum(n-1,m-pre-1,auxi,ori,tar);
}
int main(){
int n,m;
while(cin>>n>>m){
string res=findnum(n,m,'A','B','C');
cout<<res<<endl;
}
return 0;
}
英语翻译:
我们的模型在2014年的WMT英德翻译任务上实现了28.4的BLUE分数,相较于现存最好的模型也有提升,包括比集成模型提升了2个BLUE。在2014年的WMT英法翻译任务上,我们的模型在经过3.6天在八块GPU上的训练后展现出最新的单模型41.8的BLUE分数,这对于最好的语言模型的训练成本是非常小的。我们的结果表明transformer模型对于其他任务的泛化性很好------通过在大规模和有限数据集上应用英语成分句法分析任务。
