2024.7.31模拟赛12
模拟赛
打的最好的一场?
T1
题目描述
发现 \(z \in [0,999]\),果断选择枚举 \(z\)。然后枚举 \(z\) 的拆分,算出现次数统计。
注意我们只需要记录两两互质的情况,不互质的会在统计出现次数时算到。
最后由于求的是区间,小容斥一下。
code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int mod = 1e9+7;
LL a,b,c,d,ans;
LL work(LL n,LL m)
{
LL res=0;
for(int i=1;i<=min(n+m,999ll);i++)
{
for(int j=1;j<i;j++)
{
if(__gcd(i-j,j)!=1) continue;
LL tmp=min(n/(i-j),m/j);
res=(res+tmp*i)%mod;
}
}
return res;
}
int main()
{
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
ans=((work(b,d)-(work(b,c-1)+work(a-1,d))%mod+mod)+work(a-1,c-1))%mod;
printf("%lld\n",ans);
return 0;
}
T2 Shuffle Permutation
无论行列如何交换,两个在同一行的数还在同一行,在同一列的还在同一列。
也就是行的变换与列的变换完全是独立的,我们可以单独算方案再乘起来。
然后先考虑列交换,发现如果 \((a,b),(b,c)\) 分别可以交换,那 \((a,b,c)\) 之间显然可以互换,也就是交换具有传递性。
所以可以用并查集维护(其实就是连通性)。最后对每个连通块内统计一下答案就行了。
code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 55,mod = 998244353;
int n,k;
int a[N][N],sz[N];
int fa[N];
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
LL ans=1,p[N];
int main()
{
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
scanf("%d%d",&n,&k);
p[1]=1; for(int i=2;i<=n;i++) p[i]=p[i-1]*i%mod;
for(int i=1;i<=n;i++) fa[i]=i,sz[i]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
}
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
bool fl=1;
for(int h=1;h<=n;h++)
{
if(a[i][h]+a[j][h]>k)
{
fl=0;break;
}
}
if(fl)
{
int fx=find(i),fy=find(j);
if(fx==fy) continue;
sz[fx]+=sz[fy]; sz[fy]=0;
fa[fy]=fx;
}
}
}
for(int i=1;i<=n;i++) if(sz[i]>1) ans=(ans*p[sz[i]])%mod;
for(int i=1;i<=n;i++) fa[i]=i,sz[i]=1;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
bool fl=1;
for(int h=1;h<=n;h++)
{
if(a[h][i]+a[h][j]>k)
{
fl=0;break;
}
}
if(fl)
{
int fx=find(i),fy=find(j);
if(fx==fy) continue;
sz[fx]+=sz[fy]; sz[fy]=0;
fa[fy]=fx;
}
}
}
for(int i=1;i<=n;i++) if(sz[i]>1) ans=(ans*p[sz[i]])%mod;
printf("%lld\n",ans);
return 0;
}
T3 亚瑟王
遇见期望 dp,先想单独算每一个的贡献,然后加起来。
既然单独计算每张牌被选的概率,那我们假设还有 \(j\) 次选牌的机会,那不选这张牌的概率是 \((1-p_i)^j\),选这张的概率就是 \(1-(1-p_i)^j\)。
然后枚举 \(i,j\)(注意期望 dp 倒叙枚举),就做完了。(现在看这么简单?!)
code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define scan __builtin_scanf
#define print __builtin_printf
#define doubl long double
const int N = 300;
int t,n,r;
doubl f[N][N],p[N],d[N];
doubl qpow(doubl a,int b)
{
doubl res=1.0;
while(b)
{
if(b&1) res=res*a;
a=a*a; b>>=1;
}
return res;
}
int main()
{
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
scan("%d",&t);
while(t--)
{
memset(f,0,sizeof(f));
scan("%d%d",&n,&r);
for(int i=1;i<=n;i++) scan("%Lf%Lf",&p[i],&d[i]);
for(int i=n;i>=1;i--)
{
for(int j=1;j<=r;j++)
{
doubl tmp=qpow(1.0-p[i],j);
f[i][j]=f[i+1][j]*tmp+(f[i+1][j-1]+d[i])*(1.0-tmp);
}
}
print("%.10Lf\n",f[1][r]);
}
return 0;
}
T4 Serega and Fun
vector
立大功。
我的分块复杂度假的,没有维护块长,假如每次都将最后一个数放进第一个块,最后卡到 \(n^2\) 的。
正解就是把 vector
,换成 deque
。每次修改操作都将块多出的一个放到下一个块里。
false code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5+1,S = 1000;
int n,q,a[N],bl,tot,ans,cnt[105][N];
vector<int> v[105];
void mdf(int l,int r)
{
int tmp1=1,tmp2=1;
while(tmp1<tot&&v[tmp1].size()<l)
{
l-=v[tmp1].size(); r-=v[tmp1].size();
tmp1++,tmp2++;
}
while(tmp2<tot&&v[tmp2].size()<r)
{
r-=v[tmp2].size(); tmp2++;
}
int t=v[tmp2][r-1];
cnt[tmp2][t]--; cnt[tmp1][t]++;
v[tmp2].erase(v[tmp2].begin()+r-1);
v[tmp1].insert(v[tmp1].begin()+l-1,t);
}
int que(int l,int r,int k)
{
int t1=1,res=0;
while(t1<tot&&v[t1].size()<l) l-=v[t1].size(),r-=v[t1].size(),t1++;
if(r<=v[t1].size())
{
for(int i=l-1;i<=r-1;i++)
{
if(v[t1][i]==k) res++;
}
}
else
{
for(int i=l-1;i<v[t1].size();i++) if(v[t1][i]==k) res++;
r-=v[t1].size(); t1++;
while(t1<tot&&v[t1].size()<r) r-=v[t1].size(),res+=cnt[t1][k],t1++;
for(int i=0;i<r;i++) if(v[t1][i]==k) res++;
}
return res;
}
int main()
{
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
scanf("%d",&n); tot=1;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
v[tot].push_back(a[i]);
cnt[tot][a[i]]++;
if(v[tot].size()>=S) tot++;
}
scanf("%d",&q);
int ans=0;
while(q--)
{
int c; scanf("%d",&c);
if(c==1)
{
int x,y; scanf("%d%d",&x,&y);
x=((x+ans-1)%n)+1; y=((y+ans-1)%n)+1;
if(x>y) swap(x,y);
mdf(x,y);
}
else
{
int x,y,z; scanf("%d%d%d",&x,&y,&z);
x=((x+ans-1)%n)+1; y=((y+ans-1)%n)+1; z=((z+ans-1)%n)+1;
if(x>y) swap(x,y);
ans=que(x,y,z);
printf("%d\n",ans);
}
}
return 0;
}