木桩:
链接:https://ac.nowcoder.com/acm/contest/11199/A
分析:首先考虑一个小木桩前有x个大木桩 后有y个大木桩
则这个小木桩的贡献就是x×y-x 很明显均值不等式得到x和y尽量均分才能答案最大
如果a为偶数那么恰好前后各一半
如果a为奇数那么多的那一个放在后面一定最优
code:
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
int T;
void solve();
int main(){
cin>>T;
while(T--)solve();
return 0;
}
void solve(){
ll a,b;
scanf("%lld%lld",&a,&b);
ll t1=a/2;
ll t2=t1;
if(a%2)t2++;
cout<<b*(t2-1)*t1<<endl;
}
游戏:
链接:https://ac.nowcoder.com/acm/contest/11199/B
分析:
假设第i个人获胜
因为要求每一个人的获胜概率
所以首先要求出直到前i-1轮是 剪刀/石头/步 获胜的概率(谁获胜的不重要 重要的是三者中哪个在前一轮胜出)
这个直接转移就好了
接下来几轮就只能第i个人获胜 所以这样倒着转移就好了
总结一下 本题的核心在与 前i-1轮是谁输赢不重要 只用关注是石头/剪刀/步 在第i-1轮胜出 后面几轮第i个人都必须赢
code:
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int mod=998244353;
const int maxn=1e5+7;
ll dp[maxn][3],f[3],ans[maxn],t[3],ni[maxn];
int n;
int a[maxn][3],cnt[maxn];
ll ksm(ll aa,ll bb){
ll res=1;
while(bb){
if(bb&1)res=res*aa%mod;
bb>>=1;
aa=aa*aa%mod;
}
return res;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
int tot=0;
for(int j=0;j<3;j++){
scanf("%1d",&a[i][j]);
if(a[i][j]==1)tot++;
}
cnt[i]=tot;
}
for(int i=1;i<=n;i++)ni[i]=ksm(cnt[i],mod-2);
for(int i=0;i<3;i++)
if(a[1][i]==1)
dp[1][i]=ni[1];
for(int i=2;i<=n;i++)
for(int j=0;j<3;j++)
dp[i][j]=(dp[i-1][j]*(a[i][j]+a[i][(j+1)%3])%mod+dp[i-1][(j+1)%3]*a[i][j])%mod*ni[i]%mod;
for(int i=0;i<3;i++)
if(a[n][i]==1)
t[i]=(t[i]+ni[n])%mod,t[(i-1+3)%3]=(t[(i-1+3)%3]+ni[n])%mod;
for(int i=0;i<3;i++)
f[i]=t[i];
ll tt=0;
for(int i=0;i<3;i++)
if(a[n][i]==1)
tt=(tt+dp[n-1][(i+1)%3]*ni[n]%mod)%mod;
ans[n]=tt;
for(int i=0;i<3;i++)
dp[0][i]=1;
for(int i=n-1;i>=1;i--){
ll tt=0;
for(int j=0;j<3;j++)
if(a[i][j]==1)
tt=(tt+dp[i-1][(j+1)%3]*ni[i]%mod*f[j]%mod)%mod;
t[0]=t[1]=t[2]=0;
for(int j=0;j<3;j++)
if(a[i][j]==1)
t[j]=(t[j]+ni[i])%mod,t[(j-1+3)%3]=(t[(j-1+3)%3]+ni[i])%mod;
for(int j=0;j<3;j++)
f[j]=f[j]*t[j]%mod;
ans[i]=tt;
}
for(int i=1;i<=n;i++)
cout<<ans[i]<<" ";
return 0;
}