Codeforces Round #501 (Div. 3) 翻船記
A Points in Segments
翻譯
現在有一個數軸,上面會有\(M\)個點,標號為\(1\)到\(N\),現在給你在數軸上的條\(N\)線段的起始與終止的點,問哪幾個點沒有被這樣線段覆蓋,從小到大輸出。
思路
簽到題目。感覺幾乎和一道題一樣:校門外的樹,撞題是很尷尬。思路差不多,即為開一個數組,全部賦值為\(0\),輸入的線段的時候,將其起點與終點的全部的點賦值為\(1\),最後跑一下看看那些為\(0\)的點就完事了。
Code
#include<iostream> using namespace std; int book[1001];//默認為0 int main() { int n,k,t=0; cin>>n>>k; for(int i=1;i<=n;i++) { int a,b; cin>>a>>b; for(int j=a;j<=b;j++)//標記線段的區間 book[j]=1; } for(int i=1;i<=k;i++) if(book[i]==0)//0即為沒有覆蓋 t++; cout<<t<<endl; for(int i=1;i<=k;i++) if(book[i]==0) cout<<i<<" "; return 0; }
B Obtaining the String
翻譯
給你兩個字符串\(s\)與\(t\),你每次可以交換字符串\(s\)種相鄰兩個字符,請你輸出字符串\(s\)變成\(t\)的步驟(如果輸出\(k\),代表交換了\(k\)與\(k+1\)),如果有多組解,隨意輸出一種即可。
思路
這道題一開始考慮復雜了,實際不難,這題是\(SPJ\),我是這麽想的:我們都知道任意\(1\)個字符可以通過交換相鄰的兩個字符來跑遍整個字符串。
進而可以得出:只要我們可以枚舉字符串\(t\)的每一個字符,並讓\(j\)從這個字符開始(這是為了方便後面的交換),找到字符串\(s\)中的第一個與他相等的字符,如果是合法的情況,那麽每個字符都能對上去才對,所以找不到直接\(-1\)
然後,完事了,代碼有註釋。看來\(Div3\)對於我這種蒟蒻不算太水啊!
Code
#include<iostream> #include<algorithm> using namespace std; int n,num,f,ans[1000001]; string s,t; int main() { cin>>n>>s>>t; for(int i=0;i<n;i++) { f=false; int j; for(j=i;j<n;j++) if(t[i]==s[j]) { f=true;//找到第一個相等的並跳出,記錄為找到 break; } if(f==false) return cout<<-1<<endl,0; for(int k=j-1;k>=i;--k) { ans[++num]=k; swap(s[k],s[k+1]); } } cout<<num<<endl; for(int i=1; i<=num; i++) cout<<ans[i]+1<<" ";//因為我們是下標從0開始,所以要加一 return 0; }
C Songs Compression
翻譯
給你\(n\)首歌,每首歌壓縮前大小為\(a_i\),壓縮後大小為\(b_i\),你現在的空間大小為\(m\),問你至少需要壓縮幾首歌才能使得你裝下所有的歌?
思路
一看是一道貪心,思路就是把壓縮後與壓縮前的從大到小排序後減去正常情況下要的空間,看看什麽時候能夠空間或者答案是\(-1\)。
然鵝就這麽簡單嗎?不的,看看下面的幾個坑點:
請開
long long
,會爆int
的,這點我註意到了請註意壓縮前的大小可能比壓縮後的大小還要小!(\(PS:\)我就因為這個點死在第七個點上,原因是這是個英文題,我只是個準八年級學生,直接谷歌翻譯,能理解就不錯了\(QAQ\),看來這是傳說中的反常壓縮?不過我還算聰明,最後在\(11:55\)放棄了這道題,並且去幹\(D\)題,不過剛剛看完題目就十二點整了,沒辦法只好第二天下午補上\(D\)題了\(QAQ\),啊啰嗦這麽多了)
排完順序後一定要先判斷內存夠不夠,再減去!(我一開始錯在這,\(debug\)了幾分鐘)。
有點靠基本功的感覺啊,坑多死了\(www\)。
Code
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
long long n,m,c[1000001],ans,sum;//long long許多人爆了,我~~比較細心~~,沒有炸233
bool comp(int a,int b)
{
return a>b;
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++)
{
int a,b;
cin>>a>>b;
c[i]=abs(a-b);//註意,壓縮後大小可能差為負數,這就是我這題一直死在第七個點的原因
sum+=a;
}
sort(c+1,c+n+1,comp);//排序
for(int i=1; i<=n; i++)
{
if(sum<=m)//有點坑,但是~~細心的我~~還是註意到了
break;
else
ans++,sum-=c[i];//減去
}
if(sum>m)
cout<<-1<<endl;
else
cout<<ans<<endl;
return 0;
}
Walking Between Houses
翻譯
給你一條數軸(出題人很喜歡數軸啊),上面有排列著\(n\)個點,編號為\(1\)到\(n\)(你開始在\(1\))。每次你要從一個點移動到另一個點(可以重復)。移動距離為兩點坐標之差的絕對值,問你是否能否在\(k\)次機會內裏一共移動\(s\)距離,並輸出方案。
思路
第四題還是比較難的。
毫無疑問還是貪心(出題人很喜歡貪心啊)!那麽我們分類討論,先看不合法的情況
無論如何走你也走不到那個距離
無論如何走你也會走超那個距離
看來只要能走到那個距離除外都是不合法的,因此就一個走超和走不到(我沒廢話!)。
那麽如何解決?很簡單,走不到就是每次你從最左邊走到最右邊,再從最右邊走到最左邊,這樣循環下去,一直到你走完了還不到。
走超了就是你每次走一個距離,進行\(k\)次後還是大於\(s\)。
那麽這兩個代碼好寫極了,不用我教你吧^_^。
到了合法的情況,受到不合法的啟發,我們可以想到這樣的方法:每一次啊,先從最左邊走到最右邊,再從最右邊走到最左邊,循環下去,一直到你剩下的距離不足\(n-1\)(\(n-1\)就是數軸兩個端點間的距離)的時候啊,直接走完即可(由於在此期間你只會位於數軸的兩個端點)。
但是不會那麽簡單的\(QAQ\),直接走完可不行啊,如果要走\(32\)那麽遠,\(4\)下子走完,數軸有\(11\)個點。照我們說的,當還有兩個長度的時候,我們一步走完,呀!怎麽還有一下!!
所以說,我們可以這樣想:當剩下的距離不足\(n-1\)的時候,我們嘗試分成多部走,很多種方法,我的有點麻煩,某位大佬寫的是:走\(s-k\)(\(s\)是剩下的距離)的步數。感覺自己恍然大悟了(不懂你可以算算,由於是\(s-k\),這樣就巧妙的拆分成了多部分)!
一定要用long long
(\(CF\)的題就這個尿性)!
恐怕上述的方法是最簡單的方法之一了吧,上代碼(有兩個細節在代碼裏註釋了):
Code
#include<iostream>
using namespace std;
int main()
{
long long n,k,s,a=1;
cin>>n>>k>>s;
if(s>(n-1)*k||k>s)
return cout<<"NO"<<endl,0;
cout<<"YES"<<endl;
while(k--)
{
int r=min(s-k,n-1);//選區n-1與s-k中最小的,因為當s-k比n-1大的時候,我們要先消去
s-=r;
if(a+r<=n)//看看往哪個方向走。
a+=r;
else a-=r;
cout<<a<<" ";
}
return 0;
}
可以來一起\(AFO\)麽!
Codeforces Round #501 (Div. 3) 翻船記