10.6考试总结
陷入了沉思当中........
P1063 能量项链
这应该是一道很经典的模板题了,区间DP......然后我竟然没做过!!!现在做过了....
重点就是划分区间....单纯的我考试的时候以为只能用递归来处理....实际上开循环一样的
DP一类的题目就是想出来了就异常简单,想不出来....呵呵
所以直接上代码
for(int x = 2; x <= n; ++x)
for(int l = 1, r = x; r < n2; ++l, ++r)
{
for(int k = l; k < r; ++k)
{
f[l][r] = max_(f[l][r], f[l][k] + f[k + 1][r] + num[l] * num[r + 1] * num[k + 1]);
}
if(x == n) ans = max_(ans, f[l][r]);
}
就用一个k来模拟分段位置就可以了.....所以DP要多练....
P1092 虫食算
这道题其实刚放暑假的时候就已经肝过了.....记得当时改了整整一下午....也是玄学剪枝系列
其实现在分析一下公式就很简单,就是枚举每一个字母所代表的数字,然后代入到公式中进行检验。只能优化枚举过程了。
我们可以按照先输入的字母优先进行枚举,这样可以先判定最开始枚举出来的数字能不能初步满足公式。再进行下面的枚举过程,在最开始就直接否决一些肯定会出错的方案,这样似乎可以节约不少时间。
考试的时候忘记可以直接压入优先输入的字符到队列里了.......还傻傻的用暴力....然后GG了
IL void in (int x[])//输入
{
char y;
for (int i=n-1, k=0; i>=0; --i)//因为有高精度加法的原理,所以采用倒叙输入
{
cin >> y;
x[i] = y - 'A';
if (!used[x[i]])
{
used[x[i]] = 1;
pos[k++] = x[i];
}
}
}
现在已经快无法直视以前的代码了....不过以前还有注释的习惯....现在都懒得写了....因为Linux和win会有乱码
解决完输入的问题自然就稍微简单了一些.....
然后就是一个小剪枝就可以了
就是因为是加法,就可以在枚举出两个加数的时候直接手算和的数字,然后通过算出的数字判断是否可行:
1.如果算出当和所对应的数字本身就存在,就可以直接验定是否可行。
2.如果当前字母并没有对应数字,就可以计算,再判断如果算出来的数字已经存在了就肯定是错的......不存在自然就填入就可以了
IL bool prune (int t)
{//已知a,b,c 三字母都已填数 那么 判断(a+b)%n=c (a+b+1)%n=c都不成立 已知a,b,c三者其中2个求得第3个已经被占用
for (int i=n-1; i>=0; --i)
{
if (x[a[i]] != -1 && x[b[i]] != -1 && x[c[i]] != -1)
{
if ((x[a[i]] + x[b[i]]) % n != x[c[i]] &&
(x[a[i]] + x[b[i]] + 1) % n != x[c[i]])
return 1;
else
{
if(x[a[i]] != -1 && x[b[i]] != -1 && x[c[i]] == -1)
if (y[(x[a[i]]+x[b[i]])%n] && y[(x[a[i]]+x[b[i]]+1)%n])
return 1;
if (x[a[i]]!=-1 && x[b[i]]==-1 && x[c[i]]!=-1)
if (y[(x[c[i]]-x[a[i]]+n)%n] && y[(x[c[i]]-x[a[i]]+1+n)%n])//b1=(c-a+n)%n b2=(c-a-1+n)%n
return 1;
if (x[a[i]]==-1 && x[b[i]]!=-1 && x[c[i]]!=-1)
if (y[(x[c[i]]-x[b[i]]+n)%n] && y[(x[c[i]]-x[b[i]]+n-1)%n])//a1=(c-b+n)%n a2=(c-b-1+n)%n
return 1;
}
}
}
return 0;
}
P1052 过河
一个DP题.....
本来是挺水的,就是数据大了\(10^9\),所以要考虑缩减的问题,就放肆找规律了.
洛谷上有两种方案:
1.数学推出因为 t<=10t<=10 ,因此我们可以直接将大于\(10^9\)的距离直接缩到90
2.直接用1~10的最小公倍数2520来压缩就行......(无论青蛙能跳的距离是多少,它一定可以到达距离2520处。所以在前方2520没有石头时,可以将当前点向后移2520或者将后面的点向前移2520)
不过要注意s==t(只能跳一种长度)直接特判就好....
for (int i=1;i<=l+t;i++)
for (int j=s;j<=t;j++)
{
if (i-j>=0)
f[i]=min(f[i],f[i-j]);
f[i]+=stone[i];
}
P1053 篝火晚会
只要先强行按照题目要求建立一个顺序再根据建立顺序计算交换次数就可以了
void work()
{
int ans = 0;
for (int i=1; i<=n; ++i)
{
a1[(c[i]-i+n)%n]++;
a2[(c[n-i+1]-i+n)%n]++;
}
for(int i=0; i<=n-1; i++) ans = max(ans, max(a1[i], a2[i]));
cout << n - ans << endl;
return;
}
void build()
{
c[1] = 1; c[2] = fr[1]; vis[c[1]] = vis[c[2]] = 1;
for (int i=2; i<n; ++i)
{
if (c[i-1] == ba[c[i]]) c[i+1] = fr[c[i]], vis[c[i+1]] = 1;
else if (c[i-1] == fr[c[i]]) c[i+1] = ba[c[i]], vis[c[i+1]] = 1;
else
{
cout << "-1" << endl;
exit(0);
}
}
for (int i=1; i<=n; ++i)
if (!vis[i])
{
cout << "-1" << endl;
exit(0);
}
}
稍微注意一下就是因为这个东西还是一个环,所以要正反跑一遍.......大概是这样?
P1054 等价表达式
这个考试的时候确实简单的想了一下,随机生成几个数据然后用这几个数据check一下.....
好像确实有这种打法不过但是年少无知不会生成随机数然后再用栈将运算转为后缀就可以随便浪了.....