AtCoder Beginner Contest 292(E,F,G)
AtCoder Beginner Contest 292(E,F,G)
E(图)
这个题的大意是给你一个有
对于
按照以上的条件,(自己画出几条边试试)我们就会发现,如果存在一条路径,里面的点的数量大于
这个我感觉还蛮好写的
但是,我发现了一个很新颖的写法
它是记录一个点的前面一个,一个点的后面一个
根据条件,我们可以知道,要添加边的是一个点的前面一个点和这个点和后面一个点
所以,它遍历的是中间的那一个点,然后根据他前后两个点是否连接来判断是否需要添加边
但是,我们会不会觉得如果我们以这个点作为中间点,但是后面出现一条边,可以让这个点再次成为一个中间点,但是这个点已经遍历完了,会不会导致答案错误
我目前没有发现这种情况(我自己画了一段点,然后用正向和反向都试过了,没有问题)
我觉得在遍历完点时候,把这一个点删除,原来距离为
我的代码是后面的写法
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
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 mem(a,b) memset((a),(b),sizeof(a))
const int maxn=2e3+10;;
const int mod=998244353;
int n,m;
vector<vector<int>>in,out;
vector<vector<bool>>g;
signed main ()
{
cin>>n>>m;
in.resize(n+1);
out.resize(n+1);
g=vector<vector<bool>>(n+1,vector<bool>(n+1,false));
int ans=0;
for (int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
in[v].push_back(u);
out[u].push_back(v);
g[u][v]=true;
}
for (int i=1;i<=n;i++)
{
for (auto x:in[i])
{
for (auto y:out[i])
{
if(x==y) continue;
if(!g[x][y])
{
ans++;
g[x][y]=true;
in[y].push_back(x);
out[x].push_back(y);
}
}
}
}
cout<<ans<<"\n";
system ("pause");
return 0;
}
F(计算几何)
这个题目大意就是给你一个矩形的长宽,问我们可以把一个最大边长为多少的正三角形完全放进这个矩形里面去
我觉得这个题解讲得很清楚,博客
它假设这个正三角形的一个点在这个矩形的一个顶点上,一个点在矩形的边上,我们已经知道两个点了,还已知这个角的角度,(正三角形)而且根据向量的旋转,我们可以得到第三个点的坐标范围
对于旋转,我之前了解很少,没想到有公式
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
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 mem(a,b) memset((a),(b),sizeof(a))
const int maxn=2e3+10;;
const int mod=998244353;
double A,B;
signed main ()
{
cin>>A>>B;
if(A>B)
swap(A,B);
double ans1=2*B-sqrt(3)*A;
double ans2=A/sqrt(3);
double ans=min(ans1,ans2);
ans=sqrt(A*A+ans*ans);
printf("%.15lf\n",ans);
system ("pause");
return 0;
}
G(dp)
题目大意就是给你
下面是我自己的一些理解
遍历数位,从后往前,然后对于这一位,然后再一个一个求出
然后我们再来看对于某一个位置,这
我们首先得到一个区间
如果这一段区间出现过的数字只有一个,那么在这个区间里面出现过的问号也可以变成这个数字,
那么我么假设
假设这个数字是
那么此时我们可以得到
如果这一段区间没有出现过一个数字,那么在这个区间里面出现过的问号也可以变成任何数字
所以
然后我们在根据确定一个位置而合并两个区间的情况
然后我们遍历这个位置
可以得到状态转移方程如下
在
然后还有一步,就是处理好
我感觉每一位大致可以分为三步
第一步,先遍历长度,得到不同
第二步,
第三步,更新
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
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 mem(a,b) memset((a),(b),sizeof(a))
const int maxn=45;
const int mod=998244353;
int n,m,w;
string s[maxn];
int h[11][11][maxn][maxn];
void add(int &x,int c)
{
x+=c;
if(x>=mod)
{
x-=mod;
}
return ;
}
void init()
{
for (int i=0;i<10;i++)
{
for (int j=0;j<10;j++)
{
for (int l=1;l<=n;l++)
{
for (int r=1;r<=n;r++)
{
h[i][j][l][r]=0;
}
}
}
}
return ;
}
signed main ()
{
cin>>n>>m;
vector<vector<int>>f(n+1,vector<int>(n+1,0));
vector<vector<int>>g(n+1,vector<int>(n+1,0));
for (int i=1;i<=n;i++)
{
cin>>s[i];
s[i]=" "+s[i];
}
for (int i=1;i<=n;i++)
{
f[i][i]=1;
}
for (int pos=m;pos>=1;pos--)
{
g=f;
f=vector<vector<int>>(n+1,vector<int>(n+1,0));
init();
for (int i=1;i<=n;i++)
{
for (int l=1,r=i;r<=n;l++,r++)
{
w=0;
for (int k=l;k<=r;k++)
{
if(s[k][pos]!='?')
{
w|=1ll<<(s[k][pos]-'0');
}
}
if(w==0)
{
for (int k=0;k<10;k++)
{
h[k][k][l][r]=g[l][r];//相当于把这个位置赋为k,方式有 1*g[l][r]
}
}
else if(w==(w&-w))//只有一个1的情况,那就是只出现了一种数,二进制表达只有一个1
{
w=__builtin_ctz(w);//这个1在哪一个位置
h[w][w][l][r]=g[l][r];
}
for (int mid=l;mid<r;mid++)//考虑合并
{
for (int L=0;L<10;L++)
{
for (int R=L+1;R<10;R++)
{
h[L][R][l][r]=(h[L][R-1][l][mid]*h[R][R][mid+1][r]+h[L][R][l][r])%mod;
}
}
}
for (int L=0;L<10;L++)//更新f
{
for (int R=L+1;R<10;R++)
{
add(h[L][R][l][r],h[L][R-1][l][r]);
}
add(f[l][r],h[L][9][l][r]);
}
}
}
}
int ans=f[1][n];
cout<<ans<<"\n";
system ("pause");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效