九條可憐是一個熱愛思考的女孩子。ios
九條可憐最近正在研究各類排序的性質,她發現了一種頗有趣的排序方法: Gobo sort !算法
Gobo sort 的算法描述大體以下:安全
顯然這個算法的指望時間複雜度是 \(O(n\times n!)\) 的,可是九條可憐驚奇的發現,利用量子的神奇性質,在量子系統中,能夠把這個算法的時間複雜度優化到線性。優化
九條可憐對這個排序算法進行了進一步研究,她發現若是一個序列知足一些性質,那麼 Gobo sort 會很快計算出正確的結果。爲了量化這個速度,她定義 Gobo sort 的執行輪數是步驟 \(2\) 的執行次數。spa
因而她就想到了這麼一個問題:code
如今有一個長度爲 \(n\) 的序列 \(x\) ,九條可憐會在這個序列後面加入 \(m\) 個元素,每一個元素是 \([l,r]\) 內的正整數。
她但願新的長度爲 \(n+m\) 的序列執行 Gobo sort 的指望執行輪數儘可能的多。她但願獲得這個最多的指望輪數。排序
九條可憐很聰明,她很快就算出了答案,她但願和你覈對一下,因爲這個指望輪數實在是太大了,因而她只要求你輸出對 \(998244353\) 取模的結果。遊戲
對於 \(30\%\) 的數據, \(T\leq 10\) , \(n,m,l,r\leq 8\)。
對於 \(50\%\) 的數據, \(T\leq 300,n,m,l,r,a_i\leq 300\) 。
對於 \(60\%\) 的數據, \(\sum{r-l+1}\leq 10^7\) 。
對於 \(70\%\) 的數據, \(\sum{n} \leq 2\times 10^5\) 。
對於 \(90\%\) 的數據,\(m\leq 2\times 10^5\)。
對於 \(100\%\) 的數據, \(T\leq 10^5,n\leq 2\times 10^5,m\leq 10^7,1\leq l\leq r\leq 10^9\) 。
對於 \(100\%\) 的數據, \(1\leq a_i\leq 10^9,\sum{n}\leq 2\times 10^6\) 。ci
一道不錯的簽到題。it
首先若是每一個數都不一樣,畫一畫能夠知道,有且只有惟一的一種排列是知足條件的,此時須要\(n!\)次。
可是有數相同,那麼咱們能夠強制他們有大小關係、每一種大小關係對應一種排列。若是相同的數個數分別是\(a_1,a_2...a_k\),則答案爲\(\frac{n!}{a_1!a_2!a_3!...a_k!}\)
考慮怎麼樣加數會使得答案最大:確定越平均越大(優先加個數少的數字,由於乘的分母小)。因而就維護一個相似階梯的東西貪心地加就行了。
#include<iostream> #include<algorithm> using namespace std; const int mod=998244353,N=2e5+10; int n,m,l,r,jc[11000000],a[N],b[N],c[N],t[N]; int ksm(int x,int k) { int s=1;for(;k;k>>=1,x=1ll*x*x%mod) if(k&1) s=1ll*s*x%mod;return s; } void Work() { scanf("%d%d%d%d",&n,&m,&l,&r); for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1); int ans=jc[n+m],t1=0,t2=0,top=0; for(int i=1;i<=n;i++) if(a[i]>=l&&a[i]<=r) b[++t1]=a[i]; else c[++t2]=a[i]; b[t1+1]=c[t2+1]=0; for(int i=2,res=1;i<=t2+1;i++) if(c[i]!=c[i-1]) ans=1ll*ans*ksm(jc[res],mod-2)%mod,res=1; else res++; for(int i=2,res=1;i<=t1+1;i++) if(b[i]!=b[i-1]) t[++top]=res,res=1; else res++; sort(t+1,t+top+1); int s=r-l+1-top,nw=0,i=1; for(;i<=top;i++) if(1ll*s*(t[i]-nw)<=m) m-=1ll*s*(t[i]-nw),nw=t[i],s++; else break; nw+=m/s;m%=s; ans=1ll*ans*ksm(ksm(jc[nw+1],mod-2),m)%mod; ans=1ll*ans*ksm(ksm(jc[nw],mod-2),s-m)%mod; for(;i<=top;i++) ans=1ll*ans*ksm(jc[t[i]],mod-2)%mod; printf("%d\n",ans); } int main() { int T;cin>>T;jc[0]=1; for(int i=1;i<=1e7+1e6;i++) jc[i]=1ll*jc[i-1]*i%mod; while(T--) Work(); }
九條可憐是一個富有的女孩子。她長大之後創業了,開了一個公司。
可是管理公司是一個很累人的活,員工們常常揹着可憐偷懶,可憐須要時不時對辦公室進行檢查。
可憐公司有 \(n\) 個辦公室,辦公室編號是 \(l\sim l+n-1\) ,可憐會事先制定一個順序,按照這個順序依次檢查辦公室。一開始的時候,全部辦公室的員工都在偷懶,當她檢查完編號是 \(i\) 的辦公室時候,這個辦公室的員工會認真工做,而且這個辦公室的員工通知全部辦公室編號是 \(i\) 的倍數的辦公室,通知他們老闆來了,讓他們認真工做。所以,可憐檢查完第 \(i\) 個辦公室的時候,全部編號是 \(i\) 的倍數(包括 \(i\) )的辦公室的員工會認真工做。
可憐發現了員工們通風報信的行爲,她發現,對於每種不一樣的順序 \(p\) ,都存在一個最小的 \(t(p)\) ,使得可憐按照這個順序檢查完前 \(t(p)\) 個辦公室以後,全部的辦公室都會開始認真工做。她把這個 \(t(p)\) 定義爲 \(p\) 的檢查時間。
可憐想知道全部 \(t(p)\) 的和。
可是這個結果可能很大,她想知道和對 \(10^9+7\) 取模後的結果。
對於 \(20\%\) 的數據,\(r-l+1\leq 8\)。
對於另 \(10\%\) 的數據,\(l=1\)。
對於另 \(10\%\) 的數據,\(l=2\)。
對於另 \(30\%\) 的數據,\(l\leq 200\)。
對於 \(100\%\) 的數據,\(1\leq l\leq r\leq 10^7\)。
一道簡單的組合計數問題。
若是把倍數關係畫成一張拓撲圖的話,那麼當且僅當入度爲0的點都被選了,檢查結束。
設一共有k個入度爲0的點,考慮選多少次可以選全,答案就是
\[\sum_{i=k-1}^{n-1}(i+1)C_{i}^{k-1}k!(n-k)!\]
含義是在前\(i\)次中選了\(k-1\)個,在第\(i+1\)次中選了剩下的那一個。貢獻是\(i+1\),在前\(i\)次中選出\(k-1\)次決策用來選必選點,把每一種決策是否選必選點分配好後、只須要把必選點和非必選點排列上去就是方案了,爲\(k!(n-k)!\)。
在找入度爲0的點是用線性篩,找到本身在\([l,r]\)且爲質數或最大因數不在\([l,r]\)的數。
#include<iostream> using namespace std; const int N=1e7+10,mod=1e9+7; int l,r,n,Ans,cnt,ispri[N],pri[N],jc[N],inv[N],tot; int ksm(int x,int k) { int s=1;for(;k;k>>=1,x=1ll*x*x%mod) if(k&1) s=1ll*s*x%mod;return s; } void Pre() { ispri[1]=pri[1]=1; if(l==1) {cnt=1;return;} for(int i=2;i<=r;i++) { if(!ispri[i]) pri[++tot]=i,cnt+=(i>=l); for(int j=1;j<=tot&&i*pri[j]<=r;j++) { ispri[i*pri[j]]=1; if(i<l&&i*pri[j]>=l) cnt++; if(i%pri[j]==0) break; } } } int main() { cin>>l>>r;n=r-l+1;Pre();jc[0]=inv[0]=1; for(int i=1;i<=r;i++) jc[i]=1ll*jc[i-1]*i%mod; inv[r]=ksm(jc[r],mod-2); for(int i=r-1;i>=1;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod; for(int i=cnt-1;i<=n-1;i++) (Ans+=1ll*jc[i]*inv[i-cnt+1]%mod*(i+1)%mod)%=mod; Ans=1ll*Ans*cnt%mod*jc[n-cnt]%mod; cout<<Ans<<endl; }
九條可憐是一個熱愛運動的女孩子。
這一天她去登山,她的父親爲了她的安全,僱了一些保鏢,讓他們固定地呆在在山的某些位置,來實時監視九條可憐,從而保護她。
具體來講,一座山能夠描述爲一條折線,折線的下方是岩石。這條折線有 \(n\) 個折點,每一個折點上有一個亭子,第 \(i\) 個折點的座標是 \((i,h_i)\) 。九條可憐只可能會在亭子處玩耍,那些保鏢也只會在亭子處監視可憐。
因爲技術方面的緣由,一個保鏢只能監視全部他能看獲得的,橫座標不超過他所在位置的亭子。咱們稱一個保鏢能看到一個亭子 \(p\) ,當且僅當他所在的亭子 \(q\) 和 \(p\) 的連線不通過任何一塊岩石。特別地,若是這條連線剛好通過了除了 \(p,q\) 之外的亭子,那麼咱們認爲保鏢看不到可憐。
僱傭保鏢是一件很費錢的事情,可憐的父親但願保鏢越少越好。
可憐的父親還但願獲得詳盡的僱傭保鏢的方案,他知道有些亭子可能正在維修,他想對全部的 \(1\leq l\leq r\leq n\) 計算:若是事先已知了只有區間 \([l,r]\) 的亭子能夠用來玩耍(和監視),那麼最少須要多少個保鏢,才能讓 \([l,r]\) 中的每個亭子都被監視到。
可憐的父親已經獲得了一個結果,他但願和你覈實他的結果是否正確。
對於 \(30\%\) 的數據, \(n\leq 20\) 。
對於 \(70\%\) 的數據, \(n\leq 500\) 。
對於 \(100\%\) 的數據, \(n\leq 5000\) 。
對於 \(100\%\) 的數據, \(1\leq h_i\leq 10^9\) 。
略有難度的DP。
首先能夠維護斜率最值來獲得兩點間的可見關係。(一開始覺得可見區域必定是一段區間,搞了很久的貪心結果錯了,Hack:5 1 4 5)
而後設\(f[l][r]\)表示這個區間的最少關鍵點數,那麼必定要在\(r\)處放置一個,再依次找\(r\)看不到的極大區間\([l1,r1]\),考慮在\(r1,r1+1\)中選一個點做爲關鍵點就行了。
一個須要解釋的地方就是爲何\([r1+2,r]\)都看不到\([l1,r1]\):由於\(r\)看獲得\(r1+1\)和\(r1+2\),因此\(r\)和\(r1+2\)連線的夾角要大一些、在\(r\)和\(r1+1\)連線下方;若是\(r1+2\)看獲得\(r1\)的話,則\(r1+2\)和\(r1+1\)的連線的夾角比\(r1+2\)和\(r1\)的大。夾角均爲x正半軸出發的有向角,如此一畫發現矛盾,\(r1+2\)看不到\(r1\)。
代碼很簡單,固定一個\(r\),從後往前掃\(l\)。
#include<iostream> using namespace std; const int N=5100; int n,h[N],f[N][N],see[N][N],ans; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>h[i]; for(int i=1,l=0;i<=n;i++,l=i-1) for(double mn=1e9;l>=1;l--) if(1.0*(h[i]-h[l])/(i-l)<mn) mn=1.0*(h[i]-h[l])/(i-l),see[l][i]=1; for(int r=1;r<=n;r++) for(int l=r,s=1,lst=l;l>=1;l--) { if(see[l][r]) { if(!see[l+1][r]) s+=min(f[l+1][lst],f[l+1][lst+1]); f[l][r]=s; } else { if(see[l+1][r]) lst=l; f[l][r]=s+min(f[l][lst],f[l][lst+1]); } ans^=f[l][r]; } cout<<ans<<endl; }
據說JXOI 80分就能進隊什麼鬼啊。。
這放在HN那不曉得有多少AK的。。
我作起來仍是比較輕鬆吧,100+100+30。固然T2推式子的時候有一項推錯了,瞟一眼題解發現這題確實是推式子才繼續把它推對;T3xjb貪心過了前三個點。這些都是考場上三個半小時不必定能寫出來的,因此說雖然80分能夠進隊,但真正若是是考試,本身又能不能不失誤呢?還須要斟酌、修煉。