6.30集訓模擬賽4(炸裂的一天qwq)
- 2020 年 6 月 30 日
- 筆記
T1澆水:
題目描述
- 在一條長n米,寬m米米的長方形草地上放置着k個噴水裝置。假設長方形草地的坐標範圍為[ 0 , 0 ] ~ [ n , m ],那麼第 i 個噴水裝置的位置為(ai,m/2),也就是說噴水裝置全部位於一條直線上。此外第 i 個噴水裝置能向半徑ri的圓形區域內噴水。
-
負責管理噴水裝置的園丁老大爺想知道,要想覆蓋整個草地,至少需要開啟多少個噴水裝置。
輸入格式
- 第一行三個正整數 k , n , m 。其中 m 為偶數。
- 接下來 k 行,每行兩個整數ai 和ri ,代表第 i 個噴水裝置的橫坐標和噴水半徑。
輸出格式
- 一個整數 ans 代表至少需要開啟的噴水裝置數量。若所有裝置都開啟依然不能覆蓋整個草地則輸出-1 。
樣例
樣例輸入1
9 16 6 0 5 2 5 4 5 6 5 8 5 10 5 12 5 14 5 16 5
樣例輸出1
2
樣例輸入2
8 20 2 5 3 4 1 1 2 7 2 10 2 13 3 16 2 19 4
樣例輸出2
6
數據範圍與提示
- 樣例1 解釋開啟位於4和12的噴水裝置即可。
- 30%的數據中:k ≤ 20。
- 另有20%的數據中:ri均相等。
- 100%的數據中:m≤20000,ri≤10000,n,k≤100000,ai。
分析:
- 噴水裝置在長方形的中線上,如果某個噴水裝置能噴到左上角的地方,那左下角必定能噴到。
- 如果噴水裝置的噴水半徑小於此裝置無用
- 所以我們可以預處理出每一個噴水裝置能噴到的左、右最遠的距離,然後對其左邊界進行排序,從左到右,一次枚舉花壇的未噴到的最遠點,在能噴到的裝置中找到右端點最遠的裝置。
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int k,n,m; int a,r; int cnt; struct wat{//記錄一個點的左右最遠的覆蓋範圍 double L;//double!!! double R; }w[N]; bool cmp(wat a,wat b){//按 return a.L<b.L; } int main(){ scanf("%d%d%d",&k,&n,&m);//輸入 for(int i=1;i<=k;i++){ scanf("%d%d",&a,&r); if(r*2<=m)continue;//去除一些沒用的噴水裝置 w[++cnt].L=a-sqrt(r*r-m*m/4.0);//等於也不行(噴一個線有啥用) w[cnt].R=a+sqrt(r*r-m*m/4.0); } sort(w+1,w+1+cnt,cmp);//排序 double right=0; int ans=0; while(right<n){// ans++; double s=right;//用一個s保存right值因為後面的right值要變 for(int i=1;i<=k&&w[i].L<=s;i++){ if(right<w[i].R){ right=w[i].R;//更新覆蓋的最右邊的值 } } if(right==s&&s<n){//不滿題意 printf("-1\n"); return 0; } } printf("%d\n",ans); return 0; }
T2免費餡餅:
題目描述:
- 最新推出了一種叫做「免費餡餅」的遊戲:
- 遊戲在一個舞台上進行。舞台的寬度為 w格,天幕的高度為 h格,遊戲者佔一格。
- 開始時遊戲者站在舞台的正中央,手裡拿着一個托盤。下圖為天幕的高度為 4 格時某一個時刻遊戲者接餡餅的情景。
- 遊戲開始後,從舞台天幕頂端的格子中不斷出現餡餅並垂直下落。遊戲者左右移動去接餡餅。遊戲者每秒可以向左或向右移動一格或兩格,也可以站在原地不動。
- 餡餅有很多種,遊戲者事先根據自己的口味,對各種餡餅依次打了分。同時,在 電腦的遙控下,各種餡餅下落的速度也是不一樣的,下落速度以格/秒為單位。
-
當餡餅在某一秒末恰好到達遊戲者所在的格子中,遊戲者就收集到了這塊餡餅。
-
寫一個程序,幫助我們的遊戲者收集餡餅,使得所收集餡餅的分數之和最大。
輸入格式:
- 輸入文件的第一行是用空格隔開的兩個正整數,分別給出了舞台的寬度 w ( 1到 99之間的奇數)和高度 H( 1到100 之間的整數)。
- 接下來依餡餅的初始下落時間順序給出了所有餡餅的信息。每一行給出了一塊餡餅的信息。由四個正整數組成,分別表示了餡餅的初始下落時刻(1 到1000 秒),水平位置、下落速度(1 到 100 )以及分值。遊戲開始時刻為0從 開始自左向右依次對水平方向的每格編號。
- 輸入文件中同一行相鄰兩項之間用一個或多個空格隔開
輸出格式:
T3壓縮:dp(★★★★★★★★★★★★★★★★★★★★★★★★★……)
呵呵,洛谷紫題,教練拿來當作入門題考,beng……
題目描述:
- 給一個由小寫字母組成的字符串,我們可以用一種簡單的方法來壓縮其中的重複信息。壓縮後的字符串除了小寫字母外還可以(但不是必需)包含大寫字母R 與M ,其中 M 標記重複串的開始, 重複從上一個 R(如果當前位置左邊沒有M ,則從串的開始算起)開始的解壓結果(稱為緩衝串)。
- bcdcdcdcd可以壓縮為bMcdRR。
輸入格式:
- 輸入僅一行,包含待壓縮的字符串,僅包含小寫字母,長度為n。
輸出格式:
- 輸出僅一行,即壓縮後字符串的最短長度。
樣例:
樣例輸入1:
aaaaaaa
樣例輸出1:
5
樣例輸入2:
bcdcdcdcdxcdcdcdcd
樣例輸出2:
12
數據範圍與提示:
50%的數據滿足:1≤n≤20。
100%的數據滿足:1≤n≤50。
分析:
- 設f[i][j][0]表示i到j的區間沒有M的情況:
- 如果前半段與後半段相等,f[i][j][0] = min(f[i][j][0],f[i][mid][0]+1);
- 如果[i~j],但有可能[i~k](i<k<j)可以摺疊,f[i][j][0] = min(f[i][j][0],f[i][k][0]+j-k);
- f[i][j][1]表示i到j的區間內有M的情況:
- k枚舉的是M的位置,即在k的後面放一個M:
- f[i][j][1] = min(f[i][j][1],min(f[i][k][0],f[i][k][1])+min(f[k+1][j][0],f[k+1][j][1]))
- 對區間[i , k]和[k+1,j]均有兩種選擇,然後加上M這個1。
- 最後輸出ans = max(f[i][len][0],f[1][len][1])。
#include <bits/stdc++.h>
using namespace std;
const int N=55;
char s[N];
int f[N][N][3];
bool judge(int l,int r){//判斷前一半是否和後一半相等
if((r-l+1)&1)return false;//長度為奇數
int mid=(l+r)>>1;
for(int i=l;i<=mid;i++)
if(s[i]!=s[i+mid-l+1])return false;
return true;
}
int main(){
scanf("%s",s+1);
int len = strlen(s+1);
for(int i=1;i<=len;i++)//初始化為沒有摺疊
for(int j=i;j<=len;j++)
f[i][j][0]=f[i][j][1]=(j-i+1);
for(int l=1;l<=len;l++){
for(int i=1,j;(j=i+l)<=len;i++){//i為區間起點,j為區間終點
if(judge(i,j))//區間[i,j]正好能摺疊
f[i][j][0]=min(f[i][(i+j)/2][0]+1,f[i][j][0]);
for(int k=i;k<j;k++)//枚舉區間的斷點,有可能[i,k]能摺疊
f[i][j][0]=min(f[i][j][0],f[i][k][0]+j-k);
for(int k=i;k<j;k++)//枚舉M的位置,即在k的後面加一個M
f[i][j][1]=min(f[i][j][1],std::min(f[i][k][0],f[i][k][1])+min(f[k+1][j][0],f[k+1][j][1])+1);
}
}
printf("%d\n",min(f[1][len][1],f[1][len][0]));
return 0;
}
T4槍戰Maf:(思維★★)
題目描述:
- 有 n個人,用1~n進行編號,每個人手裡有一把手槍。一開始所有人都選定一個人瞄準(有可能瞄準自己)。然後他們按某個順序開槍,且任意時刻只有一個人開槍。因此,對於不同的開槍順序,最後死的人也不同。
輸入格式:
- 輸入n 人數n<1000000
- 接下來n個數,依次為每個人的aim。
輸出格式:
- 輸出只有一行,共兩行整數,為最後死亡的最小和最大人數。
樣例輸出:
8 2 3 2 2 6 7 8 5
樣例格式:
3 5
分析:
設最大存活人數Max,最少存活人數Min
#include<bits/stdc++.h>
using namespace std;
const int N=1000100;
int n;
int aim[N];
int Min,Max;
int q[N],rd[N];
bool die[N],live[N];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&aim[i]);
rd[aim[i]]++;//存入度
}
for(int i=1;i<=n;i++){
if(rd[i]==0){
Min++;//最小必活數+1
Max++;//隊列維護的是入度為0的點
q[Max]=i;
}
}
int aa=1;
while(aa<=Max){//掃描隊列
int front=q[aa++];//取出隊首並出隊
if(die[aim[front]])continue;//隊首目標已死(多個入度為0的點指向一個點)
die[aim[front]]=1;//隊首目標必死
int faim=aim[aim[front]];//隊首目標的目標可死可不死,看決策
rd[faim]--;
live[faim]=1;//可以讓他活,但想死的時候隨時可以讓他死,在環可以最後死
if(rd[faim]==0){//雖然入度為0,但不一定是必活,所以Min不加
q[++Max]=faim;
}
}//下面處理只剩下環
for(int i=1;i<=n;i++){
if(rd[i]&&!die[i]){
int l=0,flag=0;//l記錄環大小,flag標記環上是否有live的點
for(int j=i;!die[j];j=aim[j]){
l++;
flag|=live[j];
die[j]=1;//標記已死,避免其他的再來計算
}
if(!flag&&l>1)Min++;//l=1表示自環,必死
Max+=l/2;
}
}
printf("%d %d",n-Max,n-Min);
return 0;
}
博主在沒有任何編輯器的惡劣情況下成功奪得514高地(敲了一個多小時),點贊關注頂一下唄……@^_^@……