1879C - Make it Alternating
先貼程式碼,看能不能理解
str a;
ll v[N];//裝著01化為-1,1的數的陣列
ll f[N];//裝著預處理的組合數
void moon(){
cin>>a;
n=0;
m=a.size();
eps(i,0,m+10)v[i]=0; //eps()是一個陋習,define 定義的for迴圈
for(auto p:a){
v[++n]=(p=='1'?1:-1);
}
ll res=v[1],ans=0,nres=0;
multiset<ll>s;//計數,比較方便
eps(i,2,n)
{
while(res==v[i]){
ans++;i++;//因為記住的不包括自己,所以後面是(p+1)
}
nres+=ans;
if(ans>0)
s.insert(ans);
ans=0;
res=v[i];
}
cout<<nres<<' ';
res=1;
for(auto p:s){
// if(p+1==nres)res=res%mod+1;
res=res%mod*(p+1)%mod; //所有可消除元素的連乘法,是一個乘法原理
}
res=res%mod*f[(nres)]%mod;//乘以取出來的數的階乘,用來排位置
cout<<res%mod<<endl;
}
int main()
{
icc();
f[0]=1;
eps(i,1,N)
f[i]=i%mod*f[i-1]%mod;
cin>>_;
while(_--)
moon();
return 0;
}
思想分析:
題目先要求的是最小操作次數
很容易貪心貢獻的想到,常見的標 -1,1 (當然這個題沒用
我們要交替,也就是連續不相等,那麼連續相等的元素我們只會保留一個
所以用了一個multiset裝著每一次去掉的數,最後輸出res(和)
重點的是接下來的東西
我們怎麼計算多少種操作方法,顯然每個連續的數我們都可以取走(ans-1)個留下一個,也就是一個簡單的乘法原理了,ans1 * ans2 * ans3 * ...嗎?
100010 中間三個0是我們要清理的,顯然是有順序的,我們可以先拿左邊兩個,到處拿取,看看樣例,它的拿取是有順序的!
所以我們拿出元素後我們還得排序,分析拿取順序,乘以(k)! (k是拿出元素的總和)
那麼公式就出現了 ∏(1,s.size())len * (k)! (那個特殊字元是連乘)