新高一第二期培訓開始了,雖然不是我的班也來快樂了.早上來的時候見到了新高一去軍訓的場面,還挺感動的.
然後上午並沒人問我,我就在校oj刷題,一上午整了三道,美滋滋.
p1802一看就是一個動態規劃.考慮每個樹能取的狀態和前一個樹相關,而且不止與前一個樹高度相關,還和前前一個樹相關.所以我設了四個狀態表示當前樹的高度和與前一個樹的關係.分別是:最低,中等且前一個樹更高,中等且前一個樹更低,最高.
這樣就可以開始轉移了,但是如果給f[1]的四個狀態都賦值就會使得最後的答案不明確,因爲成環的原因嘛.那麼可以考慮關於一樹的狀態再分狀態.f[i][j][k]表示1樹狀態爲j,樹i狀態爲k時的最大觀賞值.轉移也很好轉移,答案是f[n][1..4][1..4]中的最大值.但是我懶省事就複製粘貼了四個.
long long a[100010][5],f[100010][5]; long long maxx(long long a,long long b,long long c) { a=a>b?a:b; return a>c?a:c; } int main() { int n=read(); for(int i=1;i<=n;i++) { a[i][1]=read(); a[i][2]=read(); a[i][3]=read(); } //1: f[1][1]=a[1][1]; f[1][2]=f[1][3]=f[1][4]=-10000000; for(int i=2;i<=n;i++) { f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]); f[i][2]=a[i][2]+f[i-1][4]; f[i][3]=a[i][2]+f[i-1][1]; f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]); } long long ans; ans=max(f[n][3],f[n][4]); //2 f[1][2]=a[1][2]; f[1][1]=f[1][3]=f[1][4]=-10000000; for(int i=2;i<=n;i++) { f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]); f[i][2]=a[i][2]+f[i-1][4]; f[i][3]=a[i][2]+f[i-1][1]; f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]); } ans=max(ans,f[n][4]); //3 f[1][3]=a[1][2]; f[1][1]=f[1][2]=f[1][4]=-10000000; for(int i=2;i<=n;i++) { f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]); f[i][2]=a[i][2]+f[i-1][4]; f[i][3]=a[i][2]+f[i-1][1]; f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]); } ans=max(ans,f[n][1]); //4 f[1][4]=a[1][3]; f[1][1]=f[1][2]=f[1][3]=-10000000; for(int i=2;i<=n;i++) { f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]); f[i][2]=a[i][2]+f[i-1][4]; f[i][3]=a[i][2]+f[i-1][1]; f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]); } ans=maxx(ans,f[n][1],f[n][2]); cout<<ans; return 0; }
p1806讀懂了題意後考慮不寫程序的話普通人會怎麼做.應該先看最後一位能不能++,如果能就++走人,否則看倒數第二位能不能++,並且使得倒數第一位爲倒數第二位原來的字母+2.如果能就這樣做,以此類推.
那麼對於第i位只需判斷是否w-i<t-ans[i].如果可以就枚舉後面所有位,使得ans[j]=ans[j-1]+1;.
char s,t; int w; char ans[30]; void work() { for(int i=w;i;i--) if(ans[i]<t&&w-i<t-ans[i]) { ans[i]=ans[i]+1; for(int j=i+1;j<=w;j++) ans[j]=ans[j-1]+1; return ; } exit(0); } int main() { s=read()+'a'-1;t=read()+'a'-1;w=read(); for(int i=1;i<=w;i++) cin>>ans[i]; for(int i=1;i<=5;i++) { work(); for(int j=1;j<=w;j++) cout<<ans[j]; cout<<endl; } return 0; }
p1808答案就是c(m+n,m)的後一百位.我會高精度!但是除法不太行,因爲求不了逆元.
考慮在班裏求組合數,先把分子分母寫出來,然後上下消去公因數,然後再把分子乘起來的操作.類比一下,先求出1到m+n的質數並且存起來,對於需要求的組合數,只需要記錄m+1到m+n和2到n的數的質因數還剩下多少,再用高精度乘起來.高精度乘單精度還是很好寫的.
這道是我上午寫的最簡單的題了.
long long num[100000],sum[100010],k; long long ans[30]; bool zhi(int x) { for(int i=sqrt(x*1.0);i>=2;i--) if(x%i==0) return 0; return 1; } void Add(long long x) { for(int i=1;x>=num[i]&&i<=k;i++) { while(x%num[i]==0) x=x/num[i],sum[i]++; } return ; } void Minus(long long x) { for(int i=1;x>=num[i]&&i<=k;i++) { while(x%num[i]==0) x=x/num[i],sum[i]--; } return ; } void mul(long long x) { for(int i=1;i<=20;i++) ans[i]=ans[i]*x; for(int i=1;i<=20;i++) ans[i+1]+=ans[i]/100000,ans[i]=ans[i]%100000; return ; } int main() { int m=read(),n=read(); if(m<n) swap(m,n); for(int i=2;i<=m+n;i++) if(zhi(i)) k++,num[k]=i; for(int i=m+n;i>m;i--) Add(i); for(int i=2;i<=n;i++) Minus(i); ans[1]=1; for(int i=1;i<=k;i++) while(sum[i]) mul(num[i]),sum[i]--; for(int i=20;i;i--) { long long t=10000; while(t&&ans[i]/t==0) cout<<0,t=t/10; if(ans[i]) cout<<ans[i]; if(i%2) cout<<endl; } return 0; }
然後中午學弟問了我一道統計數字:
某次科研調查時得到了n(n<=200000)個自然數,每個數均不超過1500000000(1.5*10^9)。已知不相同的數不超過10000個,現在需要統計這些自然數各自出現的次數,並按照自然數從小到大的順序輸出統計結果。
他們還沒學sort,桶排序也不行,這可咋辦呢?
我一拍大腿,我會map!
作爲map的忠實粉絲,即使map常數很大,但因爲它的簡單易行(與數組相似),我一直很喜歡用它艹一些題.
map<long long,int>sum;來統計每個數的數量.然後用一個迭代器便利map裏的元素輸出即可.
map<long long,int> a; long long n,x,maxx; int main() { n=read(); while(n) a[read()]++,n--; map<long long,int>::reverse_iterator iter; for(iter = a.rend(),iter--; iter != a.rbegin(); iter--) { write(iter->first); putchar(32); write(iter->second); putchar(10); } write(iter->first); putchar(32); write(iter->second); return 0; }
最後用map艹翻了一衆sort,.