DTOJ-2022-11-14-测试-题解
测试成果
还行
A 签到题
题目链接
题面大意
Diana
有一个函数 Diana
还有一个整数
题解
显然如果进位了是不优的,如果
否则答案
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+5;
int T;
char s[N];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%s",s+1);
int n=strlen(s+1),res=0;
for(int i=1; i<=n; i++) res+=s[i]-'0';
printf("%d\n",(res==1)?10:res);
}
return 0;
}
B 大根堆
题面链接
题面大意
题解
考虑
显然
我们考虑
记
转移的话就是
新填了
调教一下式子
然后就可以
(前缀和优化是好东西)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5005, P = 998244353;
int T,n,d[N],f[N][N],g[N][N],fc[N],fci[N];
int ksm(int a, int b)
{
int res=1;
for(; b; b>>=1,a=(ll)a*a%P) if(b&1) res=(ll)a*res%P;
return res;
}
void init()
{
fc[0]=1;
for(int i=1; i<N; i++) fc[i]=(ll)fc[i-1]*i%P;
fci[N-1]=ksm(fc[N-1],P-2);
for(int i=N-1; i; i--) fci[i-1]=(ll)fci[i]*i%P; //预处理阶乘哦
}
int C(int n, int m)
{
if(n<0 or m<0 or n<m) return 0;
return (ll)fc[n]*fci[m]%P*fci[n-m]%P;
}
int main()
{
scanf("%d",&T);
init();
//for(int i=0; i<=10; i++) printf("%d %d\n",fc[i],fci[i]);
while(T--)
{
scanf("%d",&n);
memset(f,0,sizeof(f));
for(int i=1; i<=n; i++) scanf("%d",&d[i]);
f[1][0]=g[1][0]=g[1][1]=1;
/*
O(n^3) 暴力版本
for(int i=2; i<=n; i++)
for(int j=0; j<i; j++)
for(int k=0; k<=j; k++)
if(j-k<=d[i]) f[i][j]=(f[i][j]+(ll)f[i-1][k]*C(i-k-1,j-k)%P*fc[j-k]%P)%P;*/
for(int i=2; i<=n; i++)
{
for(int j=0; j<i; j++)
{
int res=g[i-1][j];
if(j-d[i]>0) res=(res-g[i-1][j-d[i]-1]+P)%P;
f[i][j]=(ll)fci[i-1-j]*res%P;
g[i][j]=(ll)fc[i-j]*f[i][j]%P;
if(j) g[i][j]=(g[i][j]+g[i][j-1])%P;
}
g[i][i]=g[i][i-1]; //记得加这个要不然转移会出问题(
}
printf("%d\n",f[n][n-1]);
}
return 0;
}
C 抽卡
题面链接
题面大意
有
记物品
求
题解
纯纯概率期望推式子题,可惜我不会(
先写题解再写题(
1.
首先我们要求
期望的线性性是个好东西! ̄ω ̄=
所以我们就要求
代回去!!
诶 20 分不就到手了吗(!( ̄︶ ̄)
2.
来来来我们来推方差
注意一个小结论:
那现在我们要推两个东西 一个是
(1)
跟刚才那个
(2)
直接考虑每种事件的概率啊!
诶诶然后就完了呢!
这就完了. 直接做是
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5005, P = 998244353;
int n,n_inv,q[N],p[N],pi[N];
int ksm(int a, int b)
{
int res=1;
for( ; b; b>>=1, a=(ll)a*a%P) if(b&1) res=(ll)a*res%P;
return res;
}
void init()
{
scanf("%d",&n); int s=0; n_inv=ksm(n,P-2);
for(int i=1; i<=n; i++) scanf("%d",&q[i]),s=(s+q[i])%P;
s=ksm(s,P-2); for(int i=1; i<=n; i++) p[i]=(ll)q[i]*s%P;
for(int i=1; i<=n; i++) pi[i]=ksm(p[i],P-2);
}
void work1()
{
int res=0;
for(int i=1; i<=n; i++) res=(res+pi[i])%P;
printf("%lld\n",(ll)res*n_inv%P);
}
void work2()
{
int res1=0,res2=0;
for(int i=1; i<=n; i++) res1=(res1+(ll)(2-p[i]+P)*pi[i]%P*pi[i]%P)%P;
res1=(ll)res1*(n-1+P)%P*n_inv%P*n_inv%P;
for(int i=1; i<=n; i++) for(int j=1; j<i; j++)
res2=(res2+(ll)pi[i]*pi[j]%P-ksm(p[i]+p[j],P-2)+P)%P;
res2=(ll)res2*2*n_inv%P*n_inv%P;
printf("%d\n",(res1-res2+P)%P);
}
int main()
{
init(); work1(); work2(); return 0;
}
D 玩游戏
题目链接
题面大意
集合
- 把
中的第一个数放入 ,取走 中的一个数 ,然后把它累积到自己的得分中。
进行
对于所有测试数据,保证
题解
暴力
图:

我们可以通过观察和手模样例得出一个结论:
放入
这个很好理解,假设
所以我们就有一个
注意到第
首先我们在
求区间第
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+5;
int n,m,q;
int a[N],s[N];
int rd()
{
int x; char ch;
while(!isdigit(ch=getchar()));
for(x=(ch^48); isdigit(ch=getchar()); x=(x<<1)+(x<<3)+(ch^48));
return x;
}
struct Seg
{
int ls,rs,dat;
} t[N<<5];
int rt[N],rt2[N],tot;
void build(int &p, int l, int r, int x, int v)
{
if(!p) p=++tot;
if(l==r) { t[p].dat+=v; return ; }
int mid=(l+r)>>1;
if(x<=mid) build(t[p].ls,l,mid,x,v);
else build(t[p].rs,mid+1,r,x,v);
t[p].dat=t[t[p].ls].dat+t[t[p].rs].dat;
}
void change(int &p, int q, int l, int r, int x, int v)
{
t[p=++tot]=t[q];
if(l==r) { t[p].dat+=v; return ; }
int mid=(l+r)>>1;
if(x<=mid) change(t[p].ls,t[q].ls,l,mid,x,v);
else change(t[p].rs,t[q].rs,mid+1,r,x,v);
t[p].dat=t[t[p].ls].dat+t[t[p].rs].dat;
}
int query(int p, int q, int l, int r, int k)
{
if(l==r) return l;
int mid=(l+r)>>1;
int lcnt=t[t[p].ls].dat-t[t[q].ls].dat;
if(k<=lcnt) return query(t[p].ls,t[q].ls,l,mid,k);
else return query(t[p].rs,t[q].rs,mid+1,r,k-lcnt);
}
int main()
{
n=rd(),m=rd(),q=rd();
for(int i=1; i<=n; i++) a[i]=rd();
for(int i=1; i<=m; i++) s[i]=rd();
for(int i=1; i<=m; i++) build(rt[0],1,n+m,s[i],1);
for(int i=1; i<=n; i++) change(rt[i],rt[i-1],1,n+m,a[i],1),change(rt2[i],rt2[i-1],1,n+m,a[i],1);
int L,R,x;
/*while(q--)
{
L=rd(),R=rd(),x=rd();
printf("%d\n",query(rt[R],rt2[L-1],1,n+m,x));
}*/
while(q--)
{
L=rd(),R=rd(),x=rd();
if(query(rt[R],rt2[L-1],1,n+m,m+1)>a[x]) { puts("-1"); continue ; }
int l=x,r=R;
while(l<r)
{
// printf("%d %d\n",l,r);
int mid=(l+r)>>1;
if(query(rt[mid],rt2[L-1],1,n+m,m+1)<=a[x]) r=mid;
else l=mid+1;
}
// printf("%d\n",l);
puts(((l-L+1)&1)?"Diana":"Ava");
}
return 0;
}
正解
别催了别催了在补题了
补完了!
注意没有强制在线,我们离线做!
从小到大处理询问,先把集合
然后以下标建线段树,就可以在线段树
时间复杂度
线段树上二分确实是好东西
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+5;
int rd()
{
int x; char ch;
while(!isdigit(ch=getchar()));
for(x=(ch^48); isdigit(ch=getchar()); x=(x<<1)+(x<<3)+(ch^48));
return x;
}
struct Sagiri
{
int l,r,dat;
} t[N<<2];
#define ls (p<<1)
#define rs (p<<1)|1
void build(int p, int l, int r)
{
t[p].l=l,t[p].r=r;
if(l==r) return ;
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
t[p].dat=t[ls].dat+t[rs].dat;
}
void change(int p, int x, int v)
{
if(t[p].l==t[p].r) { t[p].dat+=v; return ; }
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid) change(ls,x,v);
else if(x>mid) change(rs,x,v);
t[p].dat=t[ls].dat+t[rs].dat;
}
int query(int p, int l, int r)
{
if(t[p].l==l and t[p].r==r) return t[p].dat;
int mid=(t[p].l+t[p].r)>>1;
if(r<=mid) return query(ls,l,r);
else if(l>mid) return query(rs,l,r);
else return query(ls,l,mid)+query(rs,mid+1,r);
}
int query2(int p, int k)
{
if(t[p].l==t[p].r) return t[p].l;
if(t[ls].dat>=k) return query2(ls,k); // 线段树上二分
else return query2(rs,k-t[ls].dat);
}
int n,m,q,nr;
int a[N],s[N];
struct Nazuna { int l,x,r,id,ans,val; } rq[N<<1]; // 拿小荠来离线询问!
void work()
{
build(1,1,n);
int cur=0;
for(int i=1; i<=nr; i++)
{
while(cur<m and s[cur+1]<rq[i].val) cur++;
if(!rq[i].id) change(1,rq[i].x,1);
else
{
if(query(1,rq[i].l,rq[i].r)<m-cur) rq[i].ans=n+1;
else
{
int t=m-cur+((rq[i].l>1)?query(1,1,rq[i].l-1):0);
if(t==0) rq[i].ans=rq[i].x; //记得各种特判
else
{
int pos=query2(1,t);
rq[i].ans=max(pos,rq[i].x);
}
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
nr++; rq[nr].x=i,rq[nr].val=a[i];
}
for(int i=1; i<=m; i++) scanf("%d",&s[i]);
sort(s+1,s+m+1);
int l,r,x;
for(int i=1; i<=q; i++)
{
scanf("%d%d%d",&l,&r,&x);
nr++; rq[nr]=(Nazuna){l,x,r,i,0,a[x]};
}
sort(rq+1,rq+nr+1, [&] (const Nazuna &a, const Nazuna &b) { return a.val<b.val or (a.val==b.val and a.id>b.id); });
work();
sort(rq+1,rq+nr+1, [&] (const Nazuna &a, const Nazuna &b) { return a.id<b.id; });
for(int i=1; i<=nr; i++)
if(rq[i].id)
{
if(rq[i].ans>rq[i].r) puts("-1");
else puts(((rq[i].ans-rq[i].l+1)&1)?"Diana":"Ava");
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!