NOI Online #3 提高组
水壶#
题意:
给一排个水壶,有次操作,每次可以选一个壶,把里面的水倒入右边一个壶,最后把一个壶里的水喝掉,最多能喝多少水?
题解:
选出和最大的连续的个,前缀和。
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
const int N=1e6+10;
int n,m,ans;
int a[N],s[N];
inline void main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
++m;
for(int i=1;i<=n;++i)
{
cin>>a[i];
s[i]=s[i-1]+a[i];
}
for(int i=m;i<=n;++i)
{
ans=max(ans,s[i]-s[i-m]);
}
cout<<ans<<'\n';
}
}
signed main()
{
red::main();
return 0;
}
/*
*/
魔法值#
题意:
个点,条边,每个点上有点权,第天为,之后每天,节点的权值变化为前一天所有和它直接相连节点的异或和,问次,问第天号节点的权值。
题解:
变化可以看作一个矩阵的形式
我们把有边直接相连的两个点之间的邻接矩阵值记作,其它值记作
那么每次一个节点的权值变化可以写作:
其中在这里是异或和,是第天,号节点的值。
那考虑后一天的邻接矩阵值怎么由前一天得到
其实和上面的式子类似
同样是异或和。
这样就可以矩阵快速幂了,复杂度,小慢。
转移答案矩阵只要,而转移邻接矩阵要
二进制拆分,先预处理出所有二的幂次的转移矩阵
询问的时候再做快速幂,
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
const int N=100+10;
int n,m,k;
int a[N];
int f[N][N];
struct matrix
{
int g[N][N];
}T[32],ans;
inline void mul(matrix &ans,matrix T,int n,int m)
{
matrix tmp;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) tmp.g[i][j]=0;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
for(int k=1;k<=m;++k)
{
tmp.g[i][j]^=ans.g[i][k]&T.g[k][j];
}
}
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) ans.g[i][j]=tmp.g[i][j];
}
inline void fast()
{
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j) T[0].g[i][j]=f[i][j];
for(int k=1;k<=31;++k)
{
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j) T[k].g[i][j]=T[k-1].g[i][j];
mul(T[k],T[k-1],n,n);
}
}
inline void main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=m;++i)
{
int x,y;cin>>x>>y;
f[x][y]=f[y][x]=(1ll<<32)-1;
}
fast();
for(int i=1;i<=k;++i)
{
int x;cin>>x;
for(int i=1;i<=n;++i) ans.g[1][i]=a[i];
for(int k=31;k>=0;--k) if((x>>k)&1)
{
mul(ans,T[k],1,n);
}
cout<<ans.g[1][1]<<'\n';
}
}
}
signed main()
{
red::main();
return 0;
}
/*
*/
优秀子序列#
题意:
给定序列,一个优秀子序列是指,这个子序列任意两个数的与为。一个子序列的贡献是
问所有优秀子序列的贡献。
题解:
一个优秀子序列,二进制下每一位肯定只出现一次。
设是优秀子序列的二进制和是的方案数,明显可以枚举子集做到
特别注意
然后就过了,呃
还有更优秀的子集卷积做法,不会
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
const int N=1e6+10,mod=1e9+7;
int n,ans;
int c[N],dp[N];
inline int phi(int x)
{
//cout<<x<<"!!"<<endl;
int ret=x;
for(int i=2;i*i<=x;++i)
{
if(x%i==0)
{
ret=ret*(i-1)/i;
while(x%i==0) x/=i;
}
}
if(x>1) ret=ret*(x-1)/x;
//cout<<ret<<"!!!!"<<endl;
return ret;
}
inline void main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;++i)
{
int x;cin>>x;
++c[x];
}
dp[0]=1;
for(int i=1;i<=c[0];++i) dp[0]=dp[0]*2%mod;
for(int s=0;s<(1<<18);++s)
{
for(int sub=s;sub;sub=(sub-1)&s)
{
if(sub<(s^sub)) break;
dp[s]=(dp[s]+(c[sub]*dp[s^sub]))%mod;
}
if(dp[s])
{
//cout<<s<<' '<<dp[s]<<"!"<<endl;
ans=(ans+dp[s]*phi(1+s))%mod;
}
}
cout<<ans<<'\n';
}
}
signed main()
{
red::main();
return 0;
}
/*
4
0 2 2 3
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)