2014多校訓練九(HDU 4960 HDU 4961 HDU 4965 HDU 4968 HDU 4969 HDU 4970),hdu4961
HDU 4960 Another OCD Patient
題意:給你一串數字 相鄰x個數字合并成一個數字(相加)有一定代價 問 最少花費多少使得串變成迴文串
思路:
讀完題感覺像dp 資料範圍也像 就開始想怎麼表示狀態 最簡單的應該想到dp[i][j]表示i到j區間變成迴文串的最小花費 狀態想好了想做法 考慮將串分成AAAABBBBBBBCCC三段 即所有A合成一個數字 C也是 而且A和C相等 那麼B串就變成了子問題 但是A和C是不是都要枚舉呢? 這個串所有元素都是正的 那麼也就是對於一種A只能對應一種C 所以這個枚舉複雜度是O(n)的 而且每次做子問題都會至少去掉首尾2個元素 那麼複雜度也就是n^2層級
代碼:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 5010#define inf 2000000000typedef __int64 LL;int n,amt;int cost[N],dp[N][N];LL sum[N];int dfs(int l,int r){ if(l>=r) return 0; if(dp[l][r]!=inf) return dp[l][r]; int i,j; LL suml,sumr; dp[l][r]=cost[r-l+1]; for(i=l,j=r;i<j;) { suml=sum[i]-sum[l-1]; sumr=sum[r]-sum[j-1]; if(suml==sumr) { dp[l][r]=min(dp[l][r],dfs(i+1,j-1)+cost[i-l+1]+cost[r-j+1]); i++; j--; } else if(suml>sumr) j--; else i++; }}int main(){ int i,j; while(~scanf("%d",&n)) { if(!n) break; for(i=1;i<=n;i++) { scanf("%I64d",&sum[i]); sum[i]+=sum[i-1]; } for(i=1;i<=n;i++) scanf("%d",&cost[i]); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) dp[i][j]=inf; } dfs(1,n); printf("%d\n",dp[1][n]); } return 0;}HDU 4961 Boring Sum
題意:略
思路:
隊友做的 他一眼就看出來了…- -b 膜拜豬神! 做法就是正反掃兩邊 對於每個數 維護它的所有約數 這樣b和c數組相當於已知了 最後掃一遍求和
代碼:
#include <cstring>#include <cstdio>#include <cmath>#include <algorithm>#include <vector>using namespace std;typedef __int64 ll;const ll mod = 1000000009;const double eps = 1e-9;const double pi = acos(-1.0);const int M=100005;int n,m;vector<int > F[M];void init(){ int i,j; for(i=1;i<M;i++) for(j=i;j<M;j+=i) F[j].push_back(i);}int dpa[M],dpb[M];int ansa[M],ansb[M];int a[M];int main(){ init(); int i,j; int T,ca=0; while(~scanf("%d",&n)) { memset(dpa,0,sizeof(dpa)); memset(dpb,0,sizeof(dpb)); if(!n) break; for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=n;i++) { if(!dpa[a[i]]) ansa[i]=i; else ansa[i]=dpa[a[i]]; for(j=0;j<F[a[i]].size();j++) { int now=F[a[i]][j]; dpa[now]=i; } } for(i=n;i>=1;i--) { if(!dpb[a[i]]) ansb[i]=i; else ansb[i]=dpb[a[i]]; for(j=0;j<F[a[i]].size();j++) { int now=F[a[i]][j]; dpb[now]=i; } } ll ans=0; for(i=1;i<=n;i++) { int x,y; x=a[ansa[i]];y=a[ansb[i]]; ans=ans+(ll)x*y; } printf("%I64d\n",ans); } return 0;}HDU 4965 Fast Matrix Calculation
題意:給你矩陣A和B 分別是1000*6和6*1000的 求 C=AB X=C^(n^2) sum(C[i][j]%6)
思路:
利用矩陣相乘的結合律 ABABAB...ABAB = A (BA)(BA)... (BA) B 所有的BA可以處理成6*6矩陣快速冪搞 線性代數內容
代碼:
#include <iostream>#include <string.h>#include <stdio.h>using namespace std;int N;int MOD=6;typedef struct{ int m[100][100];}Matrix;void clear(Matrix &a){ memset(a.m,0,sizeof(a.m));}Matrix E;void danweiE()//單位矩陣!!!!{ int i,j; for(i=0;i<100;i++) for(j=0;j<100;j++) if(i==j)E.m[i][j]=1; else E.m[i][j]=0;}Matrix Add(Matrix a,Matrix b) //矩陣加法(%MOD) { int i,j; Matrix c; for (i=0; i<N; i++) for (j=0; j<N; j++) { c.m[i][j]=a.m[i][j]+b.m[i][j]; c.m[i][j]%=MOD; } return c; }Matrix multi(Matrix a,Matrix b)//矩陣相乘!!!{ Matrix c; int i,j,k; clear(c); for(i=0;i<N;i++) for(j=0;j<N;j++) if(a.m[i][j]) for(k=0;k<N;k++) if(b.m[j][k]) c.m[i][k]=(c.m[i][k]+a.m[i][j]*b.m[j][k])%MOD; return c;}Matrix matrix_mod(Matrix a,int k)//矩陣快速冪!!!{ danweiE(); Matrix ans=E,p=a; while(k) { if(k&1) { ans=multi(ans,p); k--; } k>>=1; p=multi(p,p); } return ans;}int x[1010][1010],y[1010][1010],tmp[1010][1010];int n,k;Matrix a,ans;void debug(){ int i,j; for(i=0;i<n;i++) for(j=0;j<k;j++) printf("%d%s",x[i][j],j==k-1?"\n":" "); for(i=0;i<k;i++) for(j=0;j<n;j++) printf("%d%s",y[i][j],j==n-1?"\n":" "); for(i=0;i<k;i++) for(j=0;j<k;j++) printf("%d%s",a.m[i][j],j==k-1?"\n":" "); for(i=0;i<k;i++) for(j=0;j<k;j++) printf("%d%s",ans.m[i][j],j==k-1?"\n":" "); } int main(){ int i,j,ii; while(scanf("%d%d",&n,&k)) { if(!n&&!k) break; N=k; for(i=0;i<n;i++) for(j=0;j<k;j++) scanf("%d",&x[i][j]),x[i][j]%=6; for(i=0;i<k;i++) for(j=0;j<n;j++) scanf("%d",&y[i][j]),y[i][j]%=6; clear(a); for(i=0;i<k;i++) for(j=0;j<k;j++) { for(ii=0;ii<n;ii++) { a.m[i][j]+=y[i][ii]*x[ii][j]; } a.m[i][j]%=6; } ans=matrix_mod(a,n*n-1); //算矩陣A^n次!!!! //debug(); for(i=0;i<n;i++) for(j=0;j<k;j++) { tmp[i][j]=0; for(ii=0;ii<k;ii++) { tmp[i][j]+=x[i][ii]*ans.m[ii][j]; } tmp[i][j]%=6; } int ans=0; for(i=0;i<n;i++) for(j=0;j<n;j++) { int tt=0; for(ii=0;ii<k;ii++) { tt+=tmp[i][ii]*y[ii][j]; } ans+=(tt%6); } printf("%d\n",ans); } return 0;}HDU 4968 Improving the GPA
題意:告訴你平均分和科目數 問 你能得到的最大績點和最小績點是多少
思路:
作為經常被卡績點的人 我表示這題想法來的很快- -b
對於最小績點 那麼一定是所有科目都先加到69 然後如果總分還有剩餘 就爭取把課堆到100 為什麼呢 因為69和100最浪費分 - -b
對於最大績點 一定是所有的都從60開始 然後向85堆 為什麼呢 因為反正長5分就是0.5績點 哪科長都一樣 長到85就沒有繼續的意義了
代碼:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 100010typedef __int64 LL;int t,n,amt;double mx,mn;double cal(int f){ if(f>=85) return 2; if(f>=80) return 1.5; if(f>=75) return 1; if(f>=70) return 0.5; return 0;}int main(){ int i,j; scanf("%d",&t); while(t--) { scanf("%d%d",&amt,&n); amt*=n; i=amt-n*69; mn=n*2; while(i>0) { if(i>=31) { mn+=2; i-=31; } else { mn+=cal(i+69); i=0; } } i=amt-n*60; mx=n*2; j=0; while(i>0&&j<n) { if(i>=25) { mx+=2; i-=25; } else { mx+=cal(i+60); i=0; } j++; } printf("%.4f %.4f\n",mn/n,mx/n); } return 0;}HDU 4969 Just a Joke
題意:隊友看的- -b 大致就是問從圓心起跑的點在時刻保持自己與圓心與圓周上的點共線的情況下能不能在D距離內追到圓周上的點
思路:完全數學題- -b 推出來特別好寫… 也不卡精度…
代碼:
#include <iostream>#include <string.h>#include <stdio.h>#include <math.h>using namespace std;int N;int MOD=6;double v1,v2,r,d,k,a;int main(){ int i,j,ii; int T; scanf("%d",&T); while(T--) { int aa,bb,cc,dd; scanf("%d%d%d%d",&aa,&bb,&cc,&dd); v1=1.0*aa;v2=1.0*bb;r=1.0*cc;d=1.0*dd; a=r*v2/v1; r=asin(r/a); double ans=a*r; if(ans>d) printf("Why give up treatment\n"); else printf("Wake up to code\n"); } return 0;}HDU 4970 Killing Monsters
題意:又是塔防遊戲… 每個塔有個攻擊範圍有個攻擊力 每個怪有個起跑位置有個血量 問幾隻怪能跑過去
思路:
從後到前掃一遍計算從x點開始到最後一共受多少傷害 (別開腦洞用什麼樹狀數組…就直接掃一遍…我很不理解為啥有人上來就資料結構…) 最後對每個怪判斷一下即可
代碼:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 100010typedef __int64 LL;int n,m,ans;LL sum[N],add[N];int main(){ int i,j,l,r,d; LL ad; while(~scanf("%d",&n)) { if(!n) break; memset(sum,0,sizeof(sum)); memset(add,0,sizeof(add)); scanf("%d",&m); while(m--) { scanf("%d%d%d",&l,&r,&d); add[r]+=d; add[l-1]-=d; } ad=0; for(i=n;i>=1;i--) { ad+=add[i]; sum[i]=sum[i+1]+ad; } //for(i=1;i<=n;i++) printf("%I64d ",sum[i]); ans=0; scanf("%d",&m); while(m--) { scanf("%I64d%d",&ad,&d); if(sum[d]<ad) ans++; } printf("%d\n",ans); } return 0;}