26牛客多校8
本场感觉题解的题意概括挺好的,故直接引用,略做修改
I
给定两两配对的选手及其初始得分,每场比赛可将m分任意分配给该组选手。求Soy在所有分配方案中可能取得的最好名次与最坏名次。
分别求最优情况和最劣情况,并对每一场比赛独立贪心处理。
考虑最少有多少人超过Soy,
为了让 Soy 尽可能高,直接让他在第一场拿到全部 m 分,因此:
此时逐场考虑其他比赛,对于(ai ,ai+1),先令前者小于后者,此时分类讨论:
- ai > b : 无论怎么分,两人都超过 Soy,贡献 2。
- ai+1 > b且 ai <= b : 至少有 1人超过。
- 两人初始分数都不超过 b:判断剩余的 m - ( b - ai )分能否让另一人也超过 b,若能则贡献 1,否则贡献 0。
第一场 (a1 ,a2)单独判断,因为 Soy 本身参与其中。
对于最多有多少人超过Soy的情况,有类似做法。最终复杂度O(n)
G
构造四个无前导零的十进制正整数,使x1,x2的前a位相同、y1,y2 的前b位相同,而x1y1与x2y2 的前c位不同,并满足长度限制
易知只要让最终的乘积恰好产生进位即可,构造。
B
统计Ushio在部分手牌已被指定时,从1到2n中选择n张牌,使其无论Fuuko如何出牌都能逐轮用不大于对方的牌应对并获胜的方案数。
考虑把 1~2n 中选入 Ushio 手牌的数字记为 1,未选入的数字记为 0。
为了保证无论 Fuuko 如何出牌,Ushio 都能应对,选出的 n 个数必须满足:对任意前缀[1,i],其中选入 Ushio 的数字数量不能少于未选入的数量。
否则,若某个前缀中 Fuuko 的数字更多,Fuuko 可以优先打出这些较小的数字,使 Ushio 被迫使用更大的数字,从而输掉比赛。
因此合法的选法等价于一个长度为 2n 的合法括号序列:
- 选入 Ushio:看作 ( ;
- 不选入 Ushio:看作 ) ;
- 最终两者数量相等。
又因为 2n 一定会被选入或者不选入,所以可以发现只需要枚举 1~2n-1,最后一个位置的状态由前面的选择唯一确定。
设计dp:令 dp[i] 表示处理完当前数字后:
转移:
- 当前数字选给 Ushio:i->i+1;
- 当前数字不选给 Ushio:i->i-1。
如果某个数字是强制选择的,就不能执行 i->i-1 的转移。
最后处理完 1~2n 后,必须让最后一个数字 2n 被选入 Ushio,因此要求当前差值为 1,所以答案是:dp[1]
特殊的,由于 Ushio 一共只能选择 n 个数字,而上述括号结构中最大的数字 2n 是特殊的最后一个位置。若强制数字 x>2n-1,说明强制数字不可能处于代码构造的有效范围内,因此直接输出 0。
B.Deep Finesse
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fep(i,j,k) for(int i=j;i<=k;i++)
#define fepp(i,j,k) for(int i=j;i<k;i++)
#define fepd(i,j,k,l) for(int i=j;i<=k;i+=l)
#define feppd(i,j,k,l) for(int i=j;i<k;i+=l)
#define fed(i,j,k) for(int i=j;i>=k;i--)
#define fedd(i,j,k) for(int i=j;i>k;i--)
#define fedp(i,j,k,l) for(int i=j;i>=k;i-=l)
#define feddp(i,j,k,l) for(int i=j;i>k;i-=l)
using namespace std;
const int N=1e5+5;
const int mod=998244353;
void solve()
{
int n,m,x;
cin>>n>>m;
vector<int> a(2*n+1);
bool F=true;
fep(i,1,m)
{
cin>>x;
if(x>2*n-1) F=false;
else a[x]=1;
}
if(!F)
{
cout<<0<<endl;
return;
}
vector<int> dp(n+1),ndp(n+1);
dp[0]=1;
fep(i,1,2*n-1)
{
fill(ndp.begin(),ndp.end(),0);
fep(j,0,n)
{
if(!dp[j]) continue;
if(j<n)ndp[j+1]=(ndp[j+1]+dp[j])%mod;
if(!a[i]&&j>0)ndp[j-1]=(ndp[j-1]+dp[j])%mod;
}
dp.swap(ndp);
}
cout<<dp[1]<<endl;
return;
}
signed main()
{
IOS
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
M
给定一系列字符串请求与容量为m的Trie前缀缓存。处理请求会计算并缓存路径上的结点,超容量时只能删除叶结点;在已知全部未来请求时,求最小总计算代价。
队友赛时T了两发,据说是操作系统课的调页算法的Bélády OPT 算法。
核心思想是 把每条 Trie 边看成一个缓存块,用 Belady 最优缓存策略——每次删除“下一次最晚才会用到”的叶子边,比较神秘,等学了操作系统再来看看()
H
给定非负整数数组。每次先任选一个元素加1,再选择一个不小于x的元素减去x;求经过若干次合法操作后能够达到的最小数组元素和。
对于每个 a[i],按 x 拆成:
其中:
- 可以看成拥有的完整 x;
- 是剩余部分。
把所有完整的 x 加起来:
贪心
如果想把某个余数 r 补成 x-1,还需要:个完整单位。
因此从最大的余数开始处理,因为余数越大,需要消耗的 sum 越少,优先补它最划算。
若:就用 sum 补满它,并令该余数变成 0:
处理完所有余数后,剩余的 sum 只能按照 x-1 的周期贡献,因此最后:
再加入答案。
所以整体就是:
将每个数拆成 和 ,把所有完整块汇总成 sum,然后优先用 sum 补最大的余数到 x-1,最后剩余的完整块按 x-1 取模。
特殊的,x=1 时 ,上述过程无法使用,因此直接把所有 a[i] 求和取模。
H. It’s a Magic, Not a Trick!
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lr(i, a, b) for(int i = a; i <= b; i++)
#define rl(i,b,a) for(int i=b;i>=a;i--)
const int maxn=1e6+10;
const int inf=4e18+10;
const int mod=998244353;
int a[maxn];
int b[maxn];
void solve()
{
int n,x;
cin>>n>>x;
int ans=0;
if(x==1)
{
lr(i,1,n)
{
cin>>a[i];
ans=(ans+a[i]%mod)%mod;
}
cout<<ans<<endl;
}
else
{
__int128 sum=0;
int ans=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=a[i]%x;
sum+=(__int128)(a[i]/x);
}
sort(b+1,b+1+n);
// cout<<(int)sum<<endl;
for(int i=n;i>=1;i--)
{
if(sum>=(x-1-b[i]))
{
sum=sum-(x-1-b[i]);
// ans=(ans+1)%mod;
b[i]=0;
}
ans=(ans+b[i])%mod;
}
ans=(ans+(sum%(x-1))%mod)%mod;
cout<<ans<<endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T = 1;
cin >> T;
while(T--)
solve();
return 0;
}
C
给定质数P与上界n。对每个1 ≤ a < b ≤ n,令x = a * b−1 mod P;统计满足 a / b > x / P 的数对(a,b)。
先把原问题化成 gcd 的求和,再利用欧拉函数的约数恒等式把它转成对 P+1 所有因数的枚举;由于 P+1 很大,因此用 Pollard-Rho + Miller-Rabin 完成质因数分解。
C.Fraction on a Ring
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define i128 __int128
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fep(i,j,k) for(int i=j;i<=k;i++)
#define fepp(i,j,k) for(int i=j;i<k;i++)
#define fepd(i,j,k,l) for(int i=j;i<=k;i+=l)
#define feppd(i,j,k,l) for(int i=j;i<k;i+=l)
#define fed(i,j,k) for(int i=j;i>=k;i--)
#define fedd(i,j,k) for(int i=j;i>k;i--)
#define fedp(i,j,k,l) for(int i=j;i>=k;i-=l)
#define feddp(i,j,k,l) for(int i=j;i>k;i-=l)
using namespace std;
const int mod=998244353;
int qpow(int a,int b,int p)
{
int r=1;
while(b)
{
if(b&1) r=(i128)r*a%p;
a=(i128)a*a%p;
b>>=1;
}
return r;
}
int gcd(int a,int b)
{
while(b)
{
int t=a%b;
a=b;
b=t;
}
return a;
}
bool isprime(int n)
{
if(n<2) return 0;
for(int p:{2,3,5,7,11,13,17,19,23,29,31,37})
{
if(n%p==0) return n==p;
}
int d=n-1,s=0;
while(!(d&1)) d>>=1,s++;
for(int a:{2,325,9375,28178,450775,9780504,1795265022})
{
if(a%n==0) continue;
int x=qpow(a%n,d,n);
if(x==1||x==n-1) continue;
bool ok=0;
fep(i,1,s-1)
{
x=(i128)x*x%n;
if(x==n-1)
{
ok=1;
break;
}
}
if(!ok) return 0;
}
return 1;
}
int rho(int n)
{
if(n%2==0) return 2;
if(n%3==0) return 3;
for(int c=1;;c++)
{
int x=2,y=2,d=1;
while(d==1)
{
x=((i128)x*x+c)%n;
y=((i128)y*y+c)%n;
y=((i128)y*y+c)%n;
d=gcd(abs(x-y),n);
}
if(d!=n) return d;
}
}
vector<int> v;
vector<pair<int,int>> f;
int n,ans;
void fact(int x)
{
if(x==1) return;
if(isprime(x))
{
v.push_back(x);
return;
}
int d=rho(x);
fact(d);
fact(x/d);
}
void dfs(int k,int d,int ph)
{
if(d>n) return;
if(k==(int)f.size())
{
ans=(ans+(i128)(ph%mod)*(n/d))%mod;
return;
}
dfs(k+1,d,ph);
int pw=1;
int pp=f[k].first-1;
fep(i,1,f[k].second)
{
if(d>n/f[k].first) break;
d*=f[k].first;
if(i==1) pw=1;
else pw*=f[k].first;
dfs(k+1,d,(i128)ph*pp%mod);
pp=(i128)pp*f[k].first%mod;
}
}
void solve()
{
cin>>n;
int P;
cin>>P;
v.clear();
f.clear();
fact(P+1);
sort(v.begin(),v.end());
for(int x:v)
{
if(f.empty()||f.back().first!=x)f.push_back({x,1});
else f.back().second++;
}
ans=0;
dfs(0,1,1);
int s=(i128)(n%mod)*((n+1)%mod)%mod;
s=s*((mod+1)/2)%mod;
s=(s-ans+mod)%mod;
s=s*((mod+1)/2)%mod;
cout<<s<<endl;
}
signed main()
{
IOS
int t;
cin>>t;
while(t--) solve();
return 0;
}

浙公网安备 33010602011771号