考试题解

    科技2024-05-17  84

    序言:

    有史以来,第一次第一名。

    被质疑。。。被某些人又开始找我的茬。。

    然后我写篇题解来澄清我并没有抄话说重启两次再加拔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[i1]+(ji+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; }

    总结:

    最后一道题,确实暑假的时候做过。。我能打出来,但是说不出某行代码什么意思,就说别人抄的,真的有意思吗?

    Processed: 0.011, SQL: 9