前言:本來在週報上誇下海口說一週補一套Div1,結果發現以前打過的好幾場Div2都沒補完,於是這幾周打算先補了打過的Div2,並且寫完題解。
(感覺以前好菜,div2只能出兩題(雖然現在還是很菜
A.Salem and Sticks (1100)
題意:有個長度分別爲的木棒,你可以花費使一根木棒的長度從變爲,求讓所有木棒滿足的最小花費與此時的。
思路:由於最大隻有100,暴力枚舉所有可能的並記錄最小費用即可,時間複雜度。
代碼:
#include<bits/stdc++.h>
using namespace std;
int n,a[1010],ans=0x3f3f3f3f,tt;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int t=1;t<=100;t++)
{
int sum=0;
for(int i=1;i<=n;i++)
sum+=min(abs(a[i]-t),min(abs(a[i]-t+1),abs(a[i]-t-1)));
if(ans>sum)
{
ans=sum;
tt=t;
}
}
cout<<tt<<" "<<ans;
}
B.Zuhair and Strings (1200)
題意:求出長度爲的字符串中,不相交且長度爲的只含一種字母的子串個數。
思路:暴力記錄所有符合條件的子串,然後找最大數量,時間複雜度。
代碼:
#include<bits/stdc++.h>
using namespace std;
int n,k,ans,mp[26];
string s;
int main()
{
cin>>n>>k>>s;
for(int i=0;i<s.size();i++)
{
int cnt=0;
for(int j=i;j<i+k;j++)
{
if(s[i]!=s[j])
{
cnt=j-i;
break;
}
}
if(!cnt)
{
mp[s[i]-'a']++;
cnt=k;
}
i+=cnt-1;
}
for(int i=0;i<26;i++)
ans=max(ans,mp[i]);
cout<<ans;
}
C.Ayoub and Lost Array (1500)
題意:存在一長度爲的數組,其中每個元素的大小都屬於,求滿足數組所有元素之和的方案數(對取模)。
思路:線性dp,用表示枚舉到數組第位時和的方案數(對取模)。則狀態轉移方程爲
由於從到共有九種轉移方法,上述方程表示從轉移到。
其中爲在中的方案數,爲。(關鍵結論)
代碼:
#include<bits/stdc++.h>
#define ll long long
#define MOD 1000000007
using namespace std;
ll n,l,r,ans,dp[200010][3];
int main()
{
cin>>n>>l>>r;
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<3;j++)
{
ll cnt=(r-j+3)/3-(l-j+2)/3;
for(int k=0;k<3;k++)
dp[i][(j+k)%3]=(dp[i][(j+k)%3]+dp[i-1][k]*cnt)%MOD;
}
}
cout<<dp[n][0];
}
D.Kilani and the Game (1900)
題意:給定一個的只由數字、’#‘和’.‘構成的圖,數字代表號玩家的初始領地,共有名玩家,每回合從號玩家開始進行次擴張,號玩家每次擴張可以讓圖中所有號點四周的’.'變爲,求出當整張圖擴張完畢的時候所有數字的數量。
思路:BFS,記錄每回合開始的所有玩家的所有源點,依次往外擴張的距離後將停止時的點壓入滾動隊列使其成爲下一輪的源點,然後重複上述過程直至所有隊列都爲空,表示遊戲結束,時間複雜度。
(Bonus:讀題時想到的另一種算法,先進行次BFS預處理出所有每一點到每個玩家最近源點的曼哈頓距離(考慮’#’)並用一個的三維數組儲存,點的編號即爲距離最小的玩家的編號,遍歷整張圖後即可統計出答案。
(口頭AC,算法並未實現,正確性和複雜度未知,但時空複雜度顯然高於原算法
代碼:
#include<bits/stdc++.h>
using namespace std;
int n,m,p,a[10];//如題
int ans[10],rod=1;//ans[i]:第i號玩家的格子數,rod:當前進行的遊戲輪數
int xy[4][2]={{1,0},{0,1},{-1,0},{0,-1}};//單位向量,便於bfs
bool vis[1010][1010];//當前點是否可行
string s[1010];//存圖
struct node
{
int x,y,s;//存座標(x,y)和節點深度s
};
queue<node> qu[10][2];//qu[i][]表示i號玩家每一輪的起始節點,滾動一維
void bfs(int x)//bfs求x號玩家第rod輪的擴張情況
{
while(!qu[x][rod&1].empty())
{
node tmp=qu[x][rod&1].front();
qu[x][rod&1].pop();
if(tmp.s>rod*a[x]&&!vis[tmp.x][tmp.y])
{
qu[x][(rod+1)&1].push(tmp);
continue;
}
if(vis[tmp.x][tmp.y])continue;
vis[tmp.x][tmp.y]=true;
ans[x]++;
for(int i=0;i<4;i++)
{
int tx=tmp.x+xy[i][0],ty=tmp.y+xy[i][1];
if(!vis[tx][ty]&&s[tx][ty]=='.')
qu[x][rod&1].push({tx,ty,tmp.s+1});
}
}
}
int main()
{
cin>>n>>m>>p;
for(int i=1;i<=p;i++)cin>>a[i];
//存圖,並在所給圖的外圍加一圈'#'
for(int i=0;i<=m+1;i++)s[0].push_back('#'),vis[0][i]=1;
for(int i=0;i<=m+1;i++)s[n+1].push_back('#'),vis[n+1][i]=1;
for(int i=1;i<=n;i++)
{
s[i].push_back('#');vis[i][0]=1;
string tmp;cin>>tmp;s[i]+=tmp;
s[i].push_back('#');vis[i][m+1]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(isdigit(s[i][j]))
qu[s[i][j]-'0'][rod&1].push({i,j,0});
else if(s[i][j]=='#')
vis[i][j]=1;
while(true)
{
int flag=0;
for(int i=1;i<=p;i++)
bfs(i);
rod++;
for(int i=1;i<=p;i++)//若所有隊列都爲空說明無法擴張,遊戲結束退出循環
for(int j=0;j<2;j++)
if(!qu[i][j].empty())
flag++;
if(!flag)break;
}
for(int i=1;i<=p;i++)
cout<<ans[i]<<" ";
return 0;
}
E.Helping Hiasat (2200)
題意:未完待續
思路:
代碼: