序言:
有史以来,第一次第一名。
被质疑。。。被某些人又开始找我的茬。。
然后我写篇题解来澄清我并没有抄话说重启两次再加拔U盘,怎么会被说是抄的。。。再说即使是做过那也不得重打吗?
数列问题:
思路 :
一道公式题。
当 n = 1 n = 1 n=1的时候,f[1] = 0;
当 n = 2 n = 2 n=2的时候,f[2] = 1;
当 n = 3 n = 3 n=3的时候,f[3] = 2;
当 n = 4 n = 4 n=4的时候,f[4] = 2;
当 n = 5 n = 5 n=5的时候,f[5] = 3;
当 n = 6 n = 6 n=6的时候,f[6] = 3;
当 n = 7 n = 7 n=7的时候,f[7] = 4;
当 n = 8 n = 8 n=8的时候,f[8] = 4;
当 n = 9 n = 9 n=9的时候,f[9] = 4;
当 n = 10 n = 10 n=10的时候,f[10] = 5;
当 n = 11 n = 11 n=11的时候,f[11] = 5;
当 n = 12 n = 12 n=12的时候,f[12] = 5;
当 n = 13 n = 13 n=13的时候, f[13] = 6;
当 n = 14 n = 14 n=14的时候, f[14] = 6;
当 n = 15 n = 15 n=15的时候, f[15] = 6;
当 n = 16 n = 16 n=16的时候, f[16] = 6;
当 n = 17 n = 17 n=17的时候, f[17] = 7;
当 n = 18 n = 18 n=18的时候, f[18] = 7;
当 n = 19 n = 19 n=19的时候, f[19] = 7;
当 n = 20 n = 20 n=20的时候, f[20] = 7;
当 n = 21 n = 21 n=21的时候, f[21] = 8;
. . . . . . . ....... .......
到这里就可以看出来规律了。。。。
一个循环,如果 a i a_i ai * a i a_i ai大于 n n n的话就把 a i a_i ai赋值给一个变量,跳出循环。
code :
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
long long T, n;
long long temp_a;
int main() {
// freopen("list.in", "r", stdin);
// freopen("list.out", "w", stdout);
scanf("%lld", &T);
while(T --) {
scanf("%lld", &n);
for(int i = 1;i <= n;i ++){
if(i * i >= n) {
temp_a = i;
break;
}
}
if(temp_a * (temp_a - 1) >= n) {
printf("%lld\n", temp_a - 2 + temp_a - 1);
}
else{
printf("%lld\n", temp_a - 1 + temp_a - 1);
}
}
return 0;
}
这道题,就是靠推嘛。。看样例都可以有些启发吧。
Teamwork:
思路:
因为题面已经说了是连续的, 所以就可以用一个线性的dp。
设dp[i]
以 i i i结尾的包装能力之和的最大值。
设一个sum为
dp[i]~
dp[j]`包装能力的最大值。
然后状态转移方程就是:
d p [ j ] = M a x ( d p [ j ] , d p [ i − 1 ] + ( j − i + 1 ) ∗ s u m ) ; dp[j] = Max(dp[j] , dp[i - 1] + (j - i + 1) * sum); dp[j]=Max(dp[j],dp[i−1]+(j−i+1)∗sum);
code:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 10005;
int dp[maxn] , s[maxn];
int sum;
int n , k;
int Max(int x, int y) {
return x > y ? x : y;
}
int main() {
// freopen("worker.in", "r", stdin);
// freopen("worker.out", "w", stdout);
scanf("%d %d", &n, &k);
for(int i = 1;i <= n;i ++) {
scanf("%d", &s[i]);
}
for(int i = 1;i <= n;i ++) {
sum = 0;
for(int j = i;j < min(i + k , n + 1);j ++) {
sum = Max(s[j] , sum);//求出最高的
dp[j] = Max(dp[j] , dp[i - 1] + (j - i + 1) * sum);//更新
}
}
printf("%d", dp[n]);
return 0;
}
}
飞行路线:
思路:
一道最短路的题。。。
分层最短路的板子。。。
对于图中的所有节点 u u u,他可以拆成 k + 1 k + 1 k+1个节点 u j u_j uj,而且j ∈ \in ∈[0,k]。
分别表示当使用 j j j 次免费通行权限后到达 u u u 号节点的状态。
对于,样例来说那个图的话(脑补)加工中。
list[i][j]为到达i用了j次免费机会的最小花费。
vis[i][j]为到达i用了j次免费机会的情况是否出现过。
对于某些路径,我们可以选择使用机会,也可以选择不使用机会。
之后就分两种情况 :
void spfa() {
int head = 1;
int tail = 2;
memset(list, 0 ,sizeof(list));
list[1][0] = ks;
list[1][1] = 0;
while(head != tail) {
int x = list[head][0];
int c = list[head][1];
for(int k = last[x];k;k = a[k].next) {
int y = a[k].y;
if(f[x][c] + a[k].dis < f[y][c]) {
f[y][c] = f[x][c] + a[k].dis;
if(vis[y][c] == false) {
vis[y][c] = true;
list[tail][0] = y;
list[tail][1] = c;
tail ++;
if(tail == a_b) {
tail = 1;
}
}
}
if(f[x][c] < f[y][c + 1] && c < d_k) {
f[y][c + 1] = f[x][c];
if(vis[y][c + 1] == false) {
vis[y][c + 1] = true;
list[tail][0] = y;
list[tail][1] = c + 1;
tail ++;
if(tail == a_b){
tail = 1;
}
}
}
}
head ++;
if(head == a_b) {
head = 1;
}
vis[x][c] = false;
}
}
公路修建问题:
思路:
一道最小生成树。。。
这道题读了题感觉还好吧。。。
总共二次排序,
一次是因为一级公路有K条,所以先把一级公路的花费排一个序,然后就把剩下的公路由二级公路的花费再排一个序,
还有些细节在代码里。
code:
sort(a + 1 , a + 1 + m , cmp);
int len = 0 , ans = 0;
for(int i = 1;i <= m;i ++) {
//第一级
if(find_set(a[i].a) != find_set(a[i].b)) {
ans = max(ans , a[i].way);
make_set(a[i].a , a[i].b);
_ans[++ len].ans = 1;
vis[a[i].num] = true;
_ans[len].t = a[i].num;
}
if(len == k) {
break;
}
}
sort(a + 1 , a + 1 + m , cmp1);
for(int i = 1;i <= m;i ++) {
//第二级
if(!vis[a[i].num] && find_set(a[i].a) != find_set(a[i].b)) {
ans = max(ans , a[i].way_2);
make_set(a[i].a , a[i].b);
vis[a[i].num] = true;
_ans[++ len].ans = 2;
_ans[len].t = a[i].num;
}
if(len == n - 1) {
break;
}
总结:
最后一道题,确实暑假的时候做过。。我能打出来,但是说不出某行代码什么意思,就说别人抄的,真的有意思吗?