每一年都奔走在自己热爱里

没有人是一座孤岛,总有谁爱着你

AtCoder Beginner Contest 307(E,F,G)

AtCoder Beginner Contest 307(E,F,G)

E(dp)

E

这个题大意就是我们需要组成一个长度为n的数组,满足两个相邻的数字不可以相等,其中,a1an也是相邻的,我们可以选择的数字为0m1,问最后有多少种不同的组成方式满足以上条件。

题目大意很简单,就是有点难想,如果a1an不相邻的,那么这个问题很简单,但是这个是相邻的,这样,我们对于最后一个位置,第一个位置是哪一个数是很重要的

我们可以记录每一位和第一位选择的数字之间的关系,是否相等

我们先假定这第一位为一个数字,后面我们只需要dp[n][0]再乘以m种不同的可能即可

然后对于每一位数字的选择

所以我们可以得到状态转移方程

dp[i][0]=dp[i1][0]×(m2)+dp[i1][1]×(n1)

dp[i][1]=dp[i1][1]

如果这一位选择的是和第一位是一样的,那么前一位只能是和第一位不一样的

如果这一位选择的是和第一位是不一样的,那么前一位可以是和第一位不一样的,选择减去前一位和第一位,前一位可以和第一位是一样的,那么这一位的选择减去第一位即可

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
#include <bitset>
#include <numeric>
using namespace std;
#define int long long 
#define LL long long
#define ios  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define eps 1e-6
#define mem(a,b) memset((a),(b),sizeof(a))
const int maxn=1e6+10;
const int mod=998244353;
int t;
int n,m;
int dp[maxn][2];
void solve()
{
  cin>>n>>m;
  dp[1][1]=1;
  dp[1][0]=0;
  for (int i=2;i<=n;i++)
  {
    dp[i][1]=dp[i-1][0];
    dp[i][0]=((dp[i-1][0]*(m-2))%mod+(dp[i-1][1]*(m-1))%mod)%mod;
  }
  int ans=dp[n][0];
  ans=(ans*m)%mod;
  cout<<ans<<"\n";
  return ;
}
signed main ()
{
  //ios;
 // cin>>t;
  t=1;
  while (t--)
  {
    solve();
  }
  system ("pause");
  return 0;
}

F(dijkstra)

F

这个题的大意就是有n个房间,m个道路,其中,最开始,有一个病毒感染了k个房间,然后有d天,其中,只要在已经感染的房间到其他未感染的房间的距离小于xi,那么这样病毒就可以传染到路的另外一个房间

问,对于每一个房间,第一次被感染的时间是多少

对于每一次,我们可以判断由上一次被感染的房间到达的下一个房间的区间

如果满足距离的条件,那么就是这一天被感染的,在前面的步骤都已经判断好了,我们需要再次更新此次被感染的房间的下一个房间的距离,后面再一次判断,知道到达最后一天

具体操作可以看代码

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
#include <bitset>
#include <numeric>
using namespace std;
#define int long long 
#define LL long long
#define ios  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define eps 1e-6
#define mem(a,b) memset((a),(b),sizeof(a))
const int maxn=3e5+10;
const int mod=998244353;
int t;
int n,m,k,d;
int a[maxn],x[maxn],ans[maxn];
vector<pair<int,int>>g[maxn];
int dis[maxn];
void solve()
{
  cin>>n>>m;
  for (int i=1;i<=n;i++)
  {
    ans[i]=-1;
    vis[i]=false;
    dis[i]=inf;
  }
  priority_queue<pair<int,int>>q;
  for (int i=1;i<=m;i++)
  {
    int u,v,val;
    cin>>u>>v>>val;
    g[u].push_back({v,val});
    g[v].push_back({u,val});
  }
  cin>>k;
  for (int i=1;i<=k;i++)
  {
    int u;
    cin>>u;
    dis[u]=0;
    ans[u]=0;
    for (auto [v,val]:g[u])
    {
      if(dis[v]>dis[u]+val)
      {
        dis[v]=dis[u]+val;
        q.push({-dis[v],v});
      }
    }
  }
  cin>>d;
  for (int i=1;i<=d;i++)
  {
    int dis1;
    cin>>dis1;
    vector<int>infected;
    while (!q.empty())
    {
      auto [dis2,u]=q.top();
      if(dis[u]>dis1) break;
      q.pop();
      if(ans[u]!=-1) continue;
      ans[u]=i;
      infected.push_back(u);
      for (auto [v,val]:g[u])
      {
        if(dis[v]>dis[u]+val)
        {
          dis[v]=dis[u]+val;
          q.push({-dis[v],v});
        }
      }
    }
    for (auto u:infected)
    {
      for (auto [v,val]:g[u])
      {
        if(dis[v]>val)
        {
          dis[v]=val;
          q.push({-dis[v],v});
        }
      }
    }
  }
  for (int i=1;i<=n;i++)
  {
    cout<<ans[i]<<"\n";
  }
  return ;
}
signed main ()
{
  //ios;
 // cin>>t;
  t=1;
  while (t--)
  {
    solve();
  }
  system ("pause");
  return 0;
}

G(dp)

G

这个题的大意为给你一个数组,我们把这个数组按照下面的操作

1,ai变成ai+1ai+1变成ai+11

2,ai变成ai1ai+1变成ai+1+1的操作数字

把这个数组的极差小于等于1(maxmin<=1)

要想极差尽量少,那么我们就可以把这sum平均分,但是可能并不能均分,那么可能存在一些数字需要多一

我们可以设计一个dp[i]代表多分出i1,答案就是多分出sum1,即dp[n][sum但是我们发现如果是一个二维的数组可能会超内存,我们可以只用dp[i]记录,每次记录上一轮的dp

然后我们在考虑每一种状态时需要的操作数量

对于每一个数字,它只有两种目标aveave+1,但是我们并不是直接的判断目标和ai之间的差,因为每一次操作可以影响两个数字,我们我们需要的是ai减去前面对这一个位置的影响,就相当于在经过前面的i1次操作后对ai的影响,变成了另外一个数字cur,ai减去他们多的,然后以cur到目标数字的差,然后就可知操作数了,关于这其中的具体操作,可以看见代码

但是对于sum,可能会出现负数,我们为了让它加n,但是平均数要减一

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
#include <bitset>
#include <numeric>
using namespace std;
#define int long long 
#define LL long long
#define ios  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define eps 1e-6
#define mem(a,b) memset((a),(b),sizeof(a))
const int maxn=5e3+10;
int t;
int n,a[maxn];
void solve()
{
  cin>>n;
  int sum=0;
  for (int i=1;i<=n;i++)
  {
    cin>>a[i];
    sum+=a[i];
  }
  int ave=sum/n;
  int mod=sum%n;
  if(mod<=0)
  {
    mod+=n;
    ave--;
  }
  vector<int>dp1(mod+2,inf);
  dp1[0]=0;
  sum=0;
  int now=0;
  for (int i=1;i<=n;i++)
  {
    vector<int>dp2(mod+2,inf);
    for (int last=0;last<=mod;last++)
    {
      int val=0;
      int need=now+last-sum;
      int cur=a[i]-need;
      val=abs(cur-(ave+1));
      if(last!=mod)dp2[last+1]=min(dp2[last+1],dp1[last]+val);
      val=abs(cur-(ave));
      dp2[last]=min(dp2[last],dp1[last]+val);
    }
    sum+=a[i];
    now+=ave;
    dp1=dp2;
  }
  int ans=dp1[mod];
  cout<<ans<<"\n";
  return ;
}
signed main ()
{
  //ios;
 // cin>>t;
  t=1;
  while (t--)
  {
    solve();
  }
  system ("pause");
  return 0;
}
posted @   righting  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示