AtCoder Beginner Contest 275(B,C,D,E,F)
AtCoder Beginner Contest 275(B,C,D,E,F)
这次vp真是太惨了(可能是我自己这几天的状态不好)
特别当我看到我的B都过不了心态就崩了(越看后面越觉得我不会写)
这个B我自己写的wa了,我觉得是在计算的过程中爆了
int x=(a%mod*b%mod*c%mod)%mod;
int y=(d%mod*e%mod*f%mod)%mod;
ans=(x-y+mod)%mod;
这个wa了
然后我加上那几行,就ac了
#include <iostream>
using namespace std;
const int maxn=100+10;
#define int long long
const int mod= 998244353;
signed main ()
{
int ans,a,b,c,d,e,f;
cin>>a>>b>>c>>d>>e>>f;
a%=mod;
b%=mod;
c%=mod;
d%=mod;
e%=mod;
f%=mod;
int x=(a%mod*b%mod*c%mod)%mod;
int y=(d%mod*e%mod*f%mod)%mod;
ans=(x-y+mod)%mod;
cout<<ans<<'\n';
system ("pause");
return 0;
}
好郁闷
C
这个我觉得没写出来翻译软件有很大的错,▼o・ェ・o▼(手动狗头),它给我翻译成方块,然后我就以为只要是平行四边形就可以了,结果是正确的翻译是正方形(虽然我不一定写出来,但是知道我题意都看错了,就很气愤)
对于判断怎么有正方形的四个顶点(遍历两个顶点,求另外两个顶点)

然后一个一个找(最多是9X9)
#include <iostream>
#include <string>
using namespace std;
string s[10];
int main ()
{
for (int i=1;i<=9;i++)
{
cin>>s[i];
s[i]=" "+s[i];
}
int ans=0;
for (int x1=1;x1<=9;x1++)
{
for (int y1=1;y1<=9;y1++)
{
if (s[x1][y1]=='.')continue;
for (int x2=1;x2<=9;x2++)
{
for (int y2=1;y2<=9;y2++)
{
if (s[x2][y2]=='.') continue;
if (x1==x2&&y1==y2) continue;//不可以是同一个点
int x3=x2+(y1-y2);
int y3=y2+(x2-x1);
int x4=x1+(y1-y2);
int y4=y1+(x2-x1);
if (x3>=1&&x3<=9&&x4>=1&&x4<=9&&y3>=1&&y3<=9&&y4>=1&&y4<=9)
{
if (s[x3][y3]=='#'&&s[x4][y4]=='#')
{
ans++;
}
}
}
}
}
}
ans=ans/4;
cout<<ans<<'\n';
system ("pause");
return 0;
}
D
一只f(0)=1,f(n)=f(n/2)+f(n/3)
但是当我看到那个n竟然有1e18,就不太敢写了
没想到这就是个记忆化搜索(看来我还是对一些题目不太敏感)
#include <iostream>
#include <unordered_map>
using namespace std;
#define int long long
unordered_map<int,int>f;
int n;
int dfs(int x)
{
if (f.count(x))return f[x];
f[x]=dfs(x/2)+dfs(x/3);
return f[x];
}
signed main ()
{
cin>>n;
f[0]=1;
cout<<dfs(n)<<'\n';
system ("pause");
return 0;
}
E
这个是要从0做到n(每一步我们可以选择1到m,每个不同的数概率都一样,是1/m),如果从i出发,走x步,终点会大于n,那么我们在走到n的时候会往回走,目的地就是n-(i+x-n)
我们需要得到到达n的概率
我看出了这个是dp,不过我的状态转移方程错了,我之前是想到他会往回走的情况,我遍历到3n,那么答案就是dp[n]+dp[3n]后来发现不对,但是错在哪儿我也不太清楚(我觉得假如这样的话,可能也会有4n,5n这样也可到达)
然后这个解法解决了会往回走的情况(一视同仁,最后得到的就只是终点)
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e3+10;
#define int long long
const int mod=998244353;
int n,m,k;
int dp[maxn][maxn];
int ksm(int x,int p)
{
int res=1;
while (p)
{
if (p&1) res=(res*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return res;
}
signed main ()
{
cin>>n>>m>>k;
int inv=ksm(m,mod-2);
dp[0][0]=1;
for (int cnt=0;cnt<=k;cnt++)//翻转cnt次
{
for(int i=0;i<n;i++)//i是起点
{
for (int j=1;j<=m;j++)//这一次翻转到的数字是j,那么意味着从i走j步
{
int t=i+j;//终点
if (t>n)
{
t=n-(t-n);
}
dp[cnt+1][t]=(dp[cnt+1][t]+dp[cnt][i]*inv)%mod;
}
}
}
int ans=0;
for (int i=0;i<=k;i++)
{
ans=(ans+dp[i][n])%mod;
}
cout<<ans<<'\n';
system ("pause");
return 0;
}
F
这个呢,是给你n个数,问我们最少可以删除最少个连续段的数,让这个数组里的和为x
会有m次询问,第i次询问的x=i
还是dp(这个我没看出来,任需努力)
dp[i][j][0];//从1到i这一段,和为j,其中第i个数删除了
dp[i][j][1];//从1到i这一段,和为j,其中第i个数保留
dp[i][j][1]=min(dp[i-1][j-a[i]][0],dp[i-1][j-a[i]][1]);//i保留的时候,他的前一个不管是保留还是删除都不会增加删除次数
dp[i][j][0]=min(dp[i-1][j][0],dp[i-1][j][1]+1);//只有上一个不是删除的时候才会增加次数
具体代码
#include <iostream>
using namespace std;
const int maxn=3e3+10;
#define int long long
const int inf=1e9+10;
int dp[maxn][maxn][2];//dp[i][j][0],1到i和为j,其中第i个删除的最小次数(0),1保留
int n,a[maxn],m;
signed main ()
{
cin>>n>>m;
for (int i=1;i<=n;i++)
{
cin>>a[i];
}
for (int i=0;i<=n;i++)//记得要预处理
{
for (int j=0;j<=m;j++)//这个j一定是到m呀
{
dp[i][j][0]=dp[i][j][1]=inf;
}
}
dp[0][0][1]=0;
for (int i=1;i<=n;i++)
{
for (int j=0;j<=m;j++)
{
if (j>=a[i])
{
dp[i][j][1]=min(dp[i-1][j-a[i]][1],dp[i-1][j-a[i]][0]);
}
dp[i][j][0]=min(dp[i-1][j][0],dp[i-1][j][1]+1);
}
}
for (int i=1;i<=m;i++)
{
int ans=min(dp[n][i][0],dp[n][i][1]);
if (ans==inf)ans=-1;
cout<<ans<<'\n';
}
system ("pause");
return 0;
}

浙公网安备 33010602011771号