Codeforces Round #818 (Div. 2)
Codeforces Round #818 (Div. 2)
赛时
A | B | C | D |
---|---|---|---|
7min | 38min | 57min | 100min |
+1 | +1 |
基准分:
排名:rk736
rating:
被 卡半小时就 NM 离谱。
哦对着看错的题面搓了二十分钟啊,没事了。
为什么有人 D 会不加取模啊……
为什么 F 连着两次网络流啊……
A
对于 ,答案只有可能是 或 。
所以输出 即可。
时间复杂度:
void work(){cin>>n,cout<<n+(n/2)*2+(n/3)*2<<'\n';}
B
就稍微倒退一下,循环每行要标记的的点即可。
反正就处理一下循环条件就行了,毕竟是 B 题。
时间复杂度:
#define L(i,j,k) for(int i=(j);i<=(k);i++)
void work(){
cin>>n>>k>>x>>y;
int t=y%k;
L(i,1,n) L(j,1,n) s[i][j]='.';
L(i,0,n-1)
for(int j=(t+i)%k;j<=n;j+=k)
s[X(x+i)][j]='X';
L(i,1,n){L(j,1,n) cout<<s[i][j];cout<<'\n';}
}
C
手搓下样例就大概能知道些规律。
首先,如果出现 的情况就直接判为无解。
对于一个数 ,如果要变成 ,要么 本来就和 相等,否则就是通过 增值。
显然, 最大只能增大到 ,直接判断即可。
时间复杂度:
#define X(i) (i>n?i-n:(i<=0?i+n:i))
#define L(i,j,k) for(int i=(j);i<=(k);i++)
void work(){
cin>>n;L(i,1,n) cin>>a[i];L(i,1,n) cin>>b[i];
bool f=0;L(i,1,n) if(a[i]>b[i]) f=1;
if(f) return cout<<"NO"<<'\n',void();
L(i,1,n) if(b[i]>b[X(i+1)]+1&&a[i]!=b[i])
return cout<<"NO"<<'\n',void();
cout<<"YES"<<'\n';
}
D
文字表述参考了 CF 上的讨论,这与我赛时做法基本一致,但得出思路的过程不同且其更具有参考价值,所以主要记录的是以上做法。
留个坑:因为答案等于 所以可以用 FFT 爆艹什么鬼。
问题是在满二叉树上讨论的。
设 为当前 下,能保证无法获胜的人的个数,那么答案就是 。
然后本人的赛时做法就是找个 的状态手摸,发现了规律,然后写上去过了无比草率。
尝试写个爆搜:
const int mod=1e9+7;
int ksm(int a,int b){
int s=1;
while(b){
if(b&1) (s*=a)%=mod;
(a*=a)%=mod;b>>=1;
}return s;
}int solve(int n,int k){
if(n<k||n<0) return 0;
if(!k) return ksm(2,n);
else return solve(n-1,k)+solve(n-1,k-1);
}
学过组合数学的话,可能会感觉上面的式子有点熟悉。
其实对于在二叉树上进行拓展的状态可以类比到杨辉三角上。
每次操作可以新增加的可控人数就是第 层的当前位的值。
或者,递推 的值,设之前一个推导的数 ,其之间的差为 次。
因为每次的选择都会被确定,也不难得到上述式子。
所以,预处理组合数,随便选一种上述思路模拟即可。
别忘了加取模。
时间复杂度:
#include <bits/stdc++.h>
#define int long long
#define L(i,j,k) for(int i=(j);i<=(k);i++)
const int N=1e5+100,mod=1e9+7;
int n,k;
int d[N],jc[N],inv[N];
void init(){
d[0]=d[2]=1,d[1]=0;L(i,3,N-10) d[i]=(i-1)*(d[i-1]+d[i-2])%mod;
jc[0]=1;L(i,1,N-10) jc[i]=jc[i-1]*i%mod;
inv[1]=1;L(i,2,N-10) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
inv[0]=1;L(i,1,N-10) inv[i]=inv[i-1]*inv[i]%mod;
}int C(int x,int y){return (jc[x]*inv[y]%mod*inv[x-y]%mod);}
int ksm(int a,int b){
int s=1;
while(b){
if(b&1) (s*=a)%=mod;
(a*=a)%=mod;b>>=1;
}return s;
}void work(){
cin>>n>>k;int sum=0;
L(i,0,(min(n,k)))
(sum+=C(n,i))%=mod;
cout<<sum;
}void work(){
int ans=ksm(2,n);
L(i,0,n) (ans-=ksm(2,i),C(n-i-1,k)-mod)%=mod;
cout<<ans;
}signed main(){init();work();}
E
参考资料:OMG_wc(幻想家协会会长)的视频题解
首先考虑暴力做法,直接枚举 ,然后 ,求出值后直接相加即可。时间复杂度:
换个思路,每次枚举 的值,此时 ,很明显我们不能直接枚举 的值,那就直接枚举 的值。
设 ,每次枚举的数是 ,则 并且 ,辗转相除法推一步就可知 。
此时 的取值个数也就是 的可取对数不难看出是 ,那就可以预处理出 的值,然后做到每次 查询。
此时的时间复杂度为: 枚举 的值, 枚举 的所有因数, 的值可以 或 预处理出来。无耻宣博
时间复杂度:
#define L(i,j,k) for(int (i)=(j);i<=(k);(i)++)
#define ll(i,j,k,l) for(int (i)=(j);i<=(k);(i)+=(l))
const int N=1e5+100;int n,p[N];
int lcm(int x,int y){return x*y/__gcd(x,y);}
void work(){
cin>>n;int ans=0;L(i,1,n) p[i]=i;
L(i,2,n) if(p[i]==i)
ll(j,i,n,i) p[j]=p[j]/i*(i-1);
L(i,1,n-2){
int t=n-i;
L(j,1,sqrt(t)) if(!(t%j)){
(ans+=lcm(i,j)*p[t/j])%=mod;
if(j!=1&&j!=t/j) (ans+=lcm(i,t/j)*p[j])%=mod;
}
}cout<<ans;
}
网络流。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)