周二至周四练题题解
周二至周四练题题解
数学作业
这个题还挺简单的。
一看
这里后者挺好想。设
显然有:
容易看出,
将
容易构造状态矩阵:
同样就很轻松可以算出转移矩阵
则
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long
int m,l;
ll n;
/*省去矩阵类和快速幂*/
void init(){
cin>>n>>m;
if(n==0){
cout<<"0\n";exit(0);
} int p=n;
while(p)
l++,p/=10;
l--;
}
void solve(){
memset(f.a,0,sizeof f.a);
f.a[0]=0,f.a[1]=1,f.a[2]=1;
memset(A.a,0,sizeof A);
A.a[1][0]=A.a[1][1]=A.a[2][1]=A.a[2][2]=1;
A.a[0][0]=10;
int pow=1;
for(int i=1;i<=l;i++){
pow=pow*10;
A.a[0][0]=pow%m;
f=f*power(A,pow-pow/10);
}
A.a[0][0]=pow*10%m;
f=f*power(A,n-pow+1);
cout<<f.a[0];
}
signed main(){
init();solve();
return 0;
}
卡片占卜
容易发现,反转操作是很烦人的。但题目中 I/O
很容易让人联想到 1/0
。这启发我们将其化为一个 0/1 序列进行操作,翻转等价于这一段所有数异或1。
但这还不够,我们时间复杂度不允许区间操作,只能搞单点。
之前说到了,等价于这一段所有数异或1,则容易联想到使用异或来搞事情。
设
那么每一次操作
由于
需要注意的是,要保证序列是正面朝上,由于原序列中
容易想到,跑最短路之后,就可以求出将两点异或1的最小代价。但这里涉及到了四个点,怎么办?枚举四个点的两两对应的最短路组合即可,只有 3 种,显然,由于最短路的最短性,一定存在某方案不会重复操作。
电压
下面定义奇环/偶环为环上节点个数的奇偶性
由于一个奇环一定不合法(头尾属性一样),若选择了一个电阻后,删掉这条边之后仍然存在奇环,则这个点不能选。
问题化为高效判断一个点是否删掉后不存在奇环。
首先是原本的奇环应该消失:即所有的奇环都应该经过这条边
其次是新生的奇环数目为0:偶环被删边之后,与奇环的交会形成奇环。(也即一个奇环被删,一个偶环被删,由于这条边在图上有奇环经过,则删掉后一个奇环和偶环会合并为一个奇环。)
那么我们取一颗树(实际上是森林)来进行操作,这里取的是DFS树,很显然,除非奇环数量唯一,否则只有可能树边产生贡献。
等价于说我们枚举没有在树上的边,判断构成的是奇环还是偶环,奇环就给所有边权加一,否则就是标记不能选。
这一步可以使用树链剖分,但事实上不需要。
可以类比 tarjan LCA算法的思想,使用一次DFS直接处理出奇偶环数量的差分数组。然后暴力枚举点判断即可。
注意这一步我们是将边视为了点,所以树的根节点即使满足条件也不能选。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define N 505000
int head[N],tot=1,ver[N<<1],nxt[N<<1],dep[N],num,s[N][2],vis[N],cnt,n,m,ans,f[N],sum[N],tag[N];
void add(int u,int v){
nxt[++tot]=head[u],ver[head[u]=tot]=v;
}
void dfs(int u,int fa){
dep[u]=dep[fa]+1,vis[u]=1;
for(int i=head[u];i;i=nxt[i]){
int v=ver[i];
if(i==f[u]||i==(f[u]^1))continue;
if(vis[v]){
if(dep[v]>dep[u])continue;
int x=(dep[u]-dep[v])&1;
s[u][x]++,s[v][x]--;
if(!x)++cnt;
}
else {
f[v]=i;
dfs(v,u);
for(int i=0;i<=1;i++)s[u][i]+=s[v][i];
}
}
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;cin>>u>>v;
add(u,v);add(v,u);
}
for(int i=1;i<=n;i++)if(!vis[i])dfs(i,0);
if(!cnt){
cout<<m<<"\n";
}
for(int i=1;i<=n;i++)ans+=(s[i][0]==cnt&&s[i][1]==0&&f[i]!=0);
ans+=(cnt==1);
cout<<ans<<"\n";
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!