2020hdu多校第二場比賽及補題
這一場我們隊只A了一題
1010Lead of Wisdom
直接爆搜,但是T了好幾發,剪了下枝
如果一個物品的a,b,c,d都比不上另外一個同種物品的a,b,c,d,那這個物品就可以直接淘汰掉了
#include<iostream> #include<algorithm> #include<vector> using namespace std; struct BB{ long long a,b,c,d; }bb; vector<BB> zz[60]; int T,n,k,t; int order[60]; long long ma = 0; bool cmp(int a,int b){ return zz[b].size()>zz[a].size(); } void dfs(int cen,long long A,long long B,long long C,long long D,long long ss){ if(cen>k) { ma = max(ma,ss); return; } long long res = 0; for(int i = 0;i<zz[order[cen]].size();i++){ long long da,db,dc,dd; da = A+zz[order[cen]][i].a; db = B+zz[order[cen]][i].b; dc = C+zz[order[cen]][i].c; dd = D+zz[order[cen]][i].d; res=max(res,(100+da)*(100+db)*(100+dc)*(100+dd)); } if(res == 0){ dfs(cen+1,A,B,C,D,ss); } else for(int i = 0;i<zz[order[cen]].size();i++){ long long da,db,dc,dd,dda,ddb,ddc,ddd; da = A+zz[order[cen]][i].a; db = B+zz[order[cen]][i].b; dc = C+zz[order[cen]][i].c; dd = D+zz[order[cen]][i].d; bool ok = true; for(int j = i+1;j<zz[order[cen]].size();j++){ dda = A+zz[order[cen]][j].a; ddb = B+zz[order[cen]][j].b; ddc = C+zz[order[cen]][j].c; ddd = D+zz[order[cen]][j].d; if(dda>=da&&ddb>=db&&ddc>=dc&&ddd>=dd){ ok = false; break; } } if(ok){ long long cd = (100+da)*(100+db)*(100+dc)*(100+dd); dfs(cen+1,da,db,dc,dd,cd); } } } int main() { cin>>T; while(T--){ cin>>n>>k; ma = 0; for(int i = 1;i<=k;i++){ zz[i].clear(); order[i] = i; } for(int i = 1;i <= n;i++){ cin>>t>>bb.a>>bb.b>>bb.c>>bb.d; zz[t].push_back(bb); } sort(order+1,order+k+1,cmp); dfs(1,0,0,0,0,0); cout<<ma<<endl; } return 0; }
1006 The Oculus
F1,F2.....F2000001對2的64次方兩兩不同餘,所以直接用 unsigned long long 自然溢位即可
這題隊友寫的程式碼,RE了兩發,我比賽時沒看這程式碼,比賽結束後,我發現他陣列開的很小,我把陣列開大交了一發,然後就A了......
#include <iostream> #include <cstdio> #define fuck unsigned long long using namespace std; const int MAXN = 1e7+7; fuck fb[MAXN]; fuck t; int main(void){ fb[1] = 1; fb[2] = 2; for(fuck i=3;i<=MAXN;i++){ fb[i] = fb[i-1]+fb[i-2]; } cin >> t; while(t--){ fuck a,b,c; fuck A=0,B=0,C=0; scanf("%lld",&a); fuck flag; for(fuck i=1;i<=a;i++){ scanf("%lld",&flag); if(flag){ A += fb[i]; } } scanf("%lld",&b); for(fuck i=1;i<=b;i++){ scanf("%lld",&flag); if(flag){ B += fb[i]; } } scanf("%lld",&c); for(fuck i=1;i<=c;i++){ scanf("%lld",&flag); if(flag){ C+=fb[i]; } } fuck result = A*B; fuck last = result - C; for(fuck i=1;i<=MAXN;i++){ if(fb[i] == last){ printf("%lld\n",i); break; } } } return 0; }
1012String Distance
比賽時看了這題,沒做出來
字串距離問題,見https://www.cnblogs.com/ruanbaitql/p/13373305.html
1007In Search of Gold
樹形dp,比賽時根本不知道怎麼做
一開始想用dp[ i ][ j ]表示以 i 為根節點的子樹,用了 j 條a邊,經過 i 節點的最長的鏈最小是多少
後來發現遞推太難了
dp[son]不能遞推dp[father],father最優時,son不一定最優,father的最優態不一定是son的最優態轉移過來的
可以想到再開一個 F [ i ][ j ], 表示以 i 為根節點的子樹,用 j 條a邊時,子樹裡離根節點 i 最遠的節點到根節點 i 的距離,
這樣F[son]可以遞推dp[father]了,但dp[father]最優了,dp[son]不是最優,還有可能超過dp[father], 所以F[son]雖然能推出最優的dp[father],但不能推出最優的max(dp[son],dp[father])。。。
正確做法是二分答案,把它變成一個判斷性問題,假設最長鏈長度小於等於ans,判斷是否成立
這次我們遞推的時候,不需要遞推出最優的max(dp[son],dp[father]),我們只要在dp[son]<=ans的前提下,遞推最優的dp[father]和F[father]
#include<iostream> #include<algorithm> #include<cstdio> using namespace std; const int MAXN = 2e5 + 7; const long long INF = 1e18 + 7; int n, K; struct EDGE { int to, next; long long a, b; }edge[MAXN * 2]; int head[MAXN], tot; void add(int u, int v, long long a, long long b) { tot++; edge[tot].to = v; edge[tot].a = a; edge[tot].b = b; edge[tot].next = head[u]; head[u] = tot; } long long F[MAXN][23];//F[i][j]表示以i為根節點,用了j條a邊,離根節點最遠的節點到根節點的距離 int son[MAXN]; void dfs(int s, int f, long long ans) { son[s] = 1; for (int i = head[s]; i; i = edge[i].next) { int po = edge[i].to; if (po == f) continue; long long a = edge[i].a, b = edge[i].b; dfs(po,s,ans); son[s] += son[po]; for (int k = min(K, son[s] - 1); k >= 0; k--) {//遍歷體積 bool flag = false; for (int x = max(0, k - (son[s]-son[po]-1) ); x <= son[po] && x <= k; x++) { //每個決策選個最優 long long mi; if (x == max(0, k - (son[s] - son[po] - 1))) { //第一個決策 if (x == 0) mi = F[po][x] + b; else if (x > son[po] - 1) mi = F[po][x - 1] + a; else mi = min(F[po][x] + b, F[po][x - 1] + a); if (F[s][k - x] + mi <= ans) {//判斷這情況會不會使dp[father]超過ans flag = true; F[s][k] = max(F[s][k - x], mi); } else F[s][k] = INF; } else if (x > son[po] - 1) mi = F[po][x - 1] + a; else mi = min(F[po][x] + b, F[po][x - 1] + a); if (F[s][k - x] + mi <= ans) { flag = true; F[s][k] = min(F[s][k],max(F[s][k - x], mi));//更新f[s][k] } } if (!flag) {//沒一個決策能選的 F[s][k] = INF; } } } } bool check(long long ans) { dfs(1, 0, ans); //cout << F[1][K] << endl; if (F[1][K] > ans) return false; return true; } int main() { //freopen("1007.in", "r", stdin); int T; int u, v; long long a, b; cin >> T; while (T--) { tot = 0; cin >> n >> K; for (int i = 1; i <= n; i++) { head[i] = 0; } for (int i = 1; i < n; i++) { scanf("%d%d%lld%lld", &u, &v, &a, &b); add(u, v, a, b); add(v, u, a, b); } long long l = 1, r, mid; r = (long long)n * (long long)1e9; while (l < r) { for (int i = 1; i <= n; i++) for (int k = 0; k <= K; k++) F[i][k] = 0; mid = l + r >> 1; if (check(mid)) r = mid; else l = mid + 1; } cout << l << endl; } return 0; }
1001Total Eclipse
還沒補...