前言:本来在周报上夸下海口说一周补一套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)
题意:未完待续
思路:
代码: