我们刚刚知道那些题的解法-4
初赛
考虑把这些数分成
double
除 int
或者 int
除 double
的返回值都是 double
,而 int
除 int
会向下取整。
300iqContest2 B
首先考虑
证明:
所以题目限制可以转化为相邻两个数的异或大于等于
利用 Trie
树优化可以做到
int n,X,a[N],f[N];
struct Trie{
struct Node{
int ch[2],val;
inline Node(){ch[0]=ch[1]=0;val=0;}
inline int operator [] (int id){return ch[id];}
}p[N*60];
int tot;
inline Trie(){
tot=1;
}
inline void Insert(int x,int v){
int now=1;
dec(i,0,60){
int k=(x>>i)&1;
if(!p[now][k]) p[now].ch[k]=++tot;
p[now].val=(p[now].val+v)%mod;
now=p[now][k];
}
p[now].val=(p[now].val+v)%mod;
}
inline int Ask(int x){
int ans=0,now=1;
dec(i,0,60){
if(!now) break;
int xk=(X>>i)&1;
int aik=(x>>i)&1;
if(!xk){
(ans+=p[p[now][aik^1]].val)%=mod;
now=p[now][aik];
}
else{
now=p[now][aik^1];
}
}
ans=(ans+p[now].val)%mod;
return ans;
}
}tr;
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);read(X);rep(i,1,n) read(a[i]);
sort(a+1,a+n+1);
rep(i,1,n){
f[i]=(tr.Ask(a[i])+1)%mod;
tr.Insert(a[i],f[i]);
}
int ans=0;
rep(i,1,n){
ans=(ans+f[i])%mod;
// printf("f[%lld]=%lld\n",i,f[i]);
}
printf("%lld\n",ans);
return 0;
}
ZR 2022.9.20 赠送赛 A
如果能处理一下两种询问,那么这道题就做完了:一棵树内所有点到某个点的路径之和。一棵树内两个点的距离之和。
容易发现在本题中,询问中任意的点都应该是题目中给定的点,且设
考虑第一个询问,可以通过第二个询问把第一个询问规模缩小,且最多缩小
考虑第二个询问只可能是以后的一个点与这一层这个点之间的询问,所以总的询问个数应该是
所以加上记忆化,总的复杂度应该是
ZR 2022.9.21 赠送赛 B
场上有一个
但是发现所有人都是等价的,如果我们给每个点标上号,设题目中小 R 所在的点编号为
接下来,设
CF812Div2E
首先考虑主对角线,也就是对角线上所有点的横纵坐标之和一样的对角线,发现每次一个物体移动都会从一个对角线移动到另一个对角线,这同时表明了不可能存在某一时刻,一个对角线上存在两个物体,也就是说,合并是不可能存在的。
现在考虑一个询问 NO
,现在考虑
观察可以得到,我们可以对一些球一起做,来得到
int Q,t,x,y;
int a[N][N];
inline void Calc(int x,int y,int c){
rep(i,0,min(120ll,x+y)){
rep(j,0,min(120ll,x+y)){
a[i][j]=0;
}
}
a[0][0]=c;
rep(i,0,x+y-1){
// printf("i=%lld\n",i);
rep(j,max(i-119ll,0ll),min(119ll,i)){
int nowx=j,nowy=i-j;
// printf("a[%lld][%lld]=%lld\n",nowx,nowy,a[nowx][nowy]);
if(a[nowx][nowy]){
if(nowx<119) a[nowx+1][nowy]+=a[nowx][nowy]/2;
if(nowy<119) a[nowx][nowy+1]+=(a[nowx][nowy]+1)/2;
a[nowx][nowy]=0;
}
}
}
}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(Q);
while(Q--){
read(t);read(x);read(y);
if(t<x+y){puts("NO");continue;}
Calc(x,y,t-x-y);int nowa=a[x][y];
Calc(x,y,t-x-y+1);int nownowa=a[x][y];
// printf("nowa=%lld nownowa=%lld\n",nowa,nownowa);
if(nowa==nownowa){
puts("NO");
}
else puts("YES");
}
return 0;
}
ZR 2022.9.21 C
我的 DP 是真的不行了。
考虑枚举最小的那个塞不下去的物品,那么比它小的都要放进去,比它大的,就是一个
XOR
这个题没有给题目链接。题目如下:
把所有
首先要去掉绝对值号,考虑枚举
暴力搜索怎么算贡献?只需要在每个节点上统计经过这个点的数有多少个,就可以知道在某一位选择
显然,一个点在搜索中被访问的次数是其祖先的个数。所以总的复杂度应当是
AGC044C
两个操作哪个都不会维护。
题解比较巧妙,考虑把所有的数放进三进制
进位的处理只需要递归到子树接着处理即可。复杂度是
int pw[13],n,ans[N],cnt;
inline void Init(){
pw[0]=1;
rep(i,1,12) pw[i]=pw[i-1]*3;
}
struct Trie{
struct Node{
int ch[3],End,tag,dep;
inline int& operator [] (const int id){return ch[id];}
}p[N];
int tot;
inline Trie(){
tot=1;Init();mset(p,0);
}
inline void C(int k){
swap(p[k][1],p[k][2]);p[k].tag^=1;
}
inline void PushDown(int k){
if(p[k].tag){
rep(i,0,2) C(p[k][i]);p[k].tag=0;
}
}
inline void Insert(int x){
int now=1;
rep(i,0,n-1){
int k=(x/pw[i])%3;
if(!p[now][k]) p[now][k]=++tot;
p[p[now][k]].dep=p[now].dep+1;
now=p[now][k];
}
p[now].End=x+1;
// printf("now=%d\n",now);
// printf("p[now].End=%d\n",p[now].End);
}
inline void R(){
C(1);
}
inline void dfs(int k){
if(!k) return;
PushDown(k);
int c2=p[k][2];
p[k][2]=p[k][1];
p[k][1]=p[k][0];
p[k][0]=c2;
dfs(p[k][0]);
}
inline void Inc(){
dfs(1);
}
inline void Dfs(int k){
if(!k) return;
PushDown(k);
rep(i,0,2) Dfs(p[k][i]);
}
inline void PushDownAll(){
Dfs(1);
}
inline void ddfs(int k,int sum){
// rep(i,0,2){
// printf("p[%d][%d]=%d\n",k,i,p[k][i]);
// }
if(!k) return;
PushDown(k);
if(!p[k][0]){
// printf("k=%d\n",k);
// printf("p[k].end=%d\n",p[k].End);
assert(p[k].End);
// printf("%d\n",p[k].End-1);
ans[p[k].End-1]=sum;
return;
}
rep(i,0,2){
ddfs(p[k][i],sum+pw[p[k].dep]*i);
}
}
inline void Print(){
PushDownAll();
ddfs(1,0);
}
}tr;
int main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);
string s;cin>>s;
rep(i,0,pw[n]-1){
tr.Insert(i);
}
// tr.Print();
// // exit(0);
int len=(int)s.length()-1;
rep(i,0,len){
if(s[i]=='S') tr.R();
else if(s[i]=='R') tr.Inc();
else assert(0);
}
tr.Print();
rep(i,0,pw[n]-1){
printf("%d ",ans[i]);
}
return 0;
}
SOJ #41
我愿称这种操作为区间覆盖加。
区间赋值是可持久化平衡树可以做的虽然我不会,但是考虑这个题是一个加法的操作。
加法!这提示我们想到卷积,考虑把一个区间
但是这里并不是直上直下的加法,考虑
#include<bits/stdc++.h>
#define mset(a,b) memset((a),(b),sizeof((a)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define dec(i,l,r) for(int i=(r);i>=(l);i--)
#define cmax(a,b) (((a)<(b))?(a=b):(a))
#define cmin(a,b) (((a)>(b))?(a=b):(a))
#define Next(k) for(int x=head[k];x;x=li[x].next)
#define vc vector
#define ar array
#define pi pair
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define N 600010
#define M 1000100
using namespace std;
typedef double dd;
typedef long double ld;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
#define int long long
typedef pair<int,int> P;
typedef vector<int> vi;
const int INF=0x3f3f3f3f;
const dd eps=1e-9;
const int mod=1004535809;
const int g=3;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
struct FastIO
{
#define MB (1<<20)
char ib[MB+100],*p,*q;
char ob[MB+100],*r,stk[128];
int tp;
FastIO(){p=q=ib,r=ob,tp=0;}
~FastIO(){fwrite(ob,1,r-ob,stdout);}
char read_char()
{
if(p==q)
{
p=ib,q=ib+fread(ib,1,MB,stdin);
if(p==q)return 0;
}
return *p++;
}
template<typename T>
void read_int(T& x)
{
char c=read_char(),l=0;
for(x=0;!isdigit(c);c=read_char())l=c;
for(;isdigit(c);c=read_char())x=x*10-'0'+c;
if(l=='-')x=-x;
}
void write_char(char c)
{
if(r-ob==MB)r=ob,fwrite(ob,1,MB,stdout);
*r++=c;
}
template<typename T>
void write_int(T x)
{
if(x<0)write_char('-'),x=-x;
do stk[++tp]=x%10+'0';
while(x/=10);
while(tp)write_char(stk[tp--]);
}
}IO;
int n,m,a[N],posi[N],Len,cnt[N],b[N];
int tr[N];
int A[N];
struct Ope{
int l,r,L;
}q[M];
inline int gel(int id){return (id-1)*Len+1;}
inline int ger(int id){return min(n,id*Len);}
inline void Gettr(int len){
rep(i,0,len-1) tr[i]=(tr[i>>1]>>1)|((i&1)?(len>>1):0);
}
inline int ksm(int a,int b,int mod){
int res=1;while(b){if(b&1){res=1ll*res*a%mod;}a=1ll*a*a%mod;b>>=1;}return res;
}
inline int inv(int x){return ksm(x,mod-2,mod);}
inline void NTT(int *f,int n,int op){
rep(i,0,n-1) if(i<tr[i]) swap(f[i],f[tr[i]]);
for(int i=2;i<=n;i<<=1){
int tg=ksm(g,(mod-1)/i,mod);
if(op==-1) tg=inv(tg);
for(int j=0;j<n;j+=i){
int now=1;
for(int k=j;k<j+i/2;k++){
int tt=now*f[k+i/2]%mod;
f[k+i/2]=(f[k]-tt+mod)%mod;
f[k]=(f[k]+tt)%mod;
now=now*tg%mod;
}
}
}
if(op==-1){
int invn=inv(n);
rep(i,0,n-1) f[i]=f[i]*invn%mod;
}
}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
IO.read_int(n);rep(i,1,n) IO.read_int(a[i]);
IO.read_int(m);
rep(i,1,m){
// read(q[i].l);read(q[i].r);read(q[i].L);
IO.read_int(q[i].l);IO.read_int(q[i].r);IO.read_int(q[i].L);
}
Len=ceil(sqrt(log2(n)*n)*2.0);
rep(i,1,n){
posi[i]=(i-1)/Len+1;
}
rep(i,1,posi[n]){
int l=gel(i),r=ger(i);
}
rep(j,1,m){
int bl=q[j].L,br=min(n,q[j].L+q[j].r-q[j].l);
int blid=posi[bl];
int brid=posi[br];
if(blid==brid){
rep(i,bl,br){
b[i]+=a[i-q[j].L+q[j].l];
}
}
else{
rep(i,bl,ger(blid)){
b[i]+=a[i-q[j].L+q[j].l];
}
rep(i,gel(brid),br){
b[i]+=a[i-q[j].L+q[j].l];
}
}
}
int len=1;
while(len<(n+1)*2) len<<=1;
Gettr(len);
NTT(a,len,1);
rep(i,1,posi[n]){
int l=gel(i),r=ger(i);
mset(cnt,0);
rep(j,1,m){
int bl=q[j].L,br=min(n,q[j].L+q[j].r-q[j].l);
int blid=posi[bl];
int brid=posi[br];
if(blid<i&&i<brid){
int len=l-bl+1;
cnt[q[j].l+len-1]++;
}
}
reverse(cnt+1,cnt+n+1);
NTT(cnt,len,1);
rep(j,0,len) cnt[j]=cnt[j]*a[j]%mod;
NTT(cnt,len,-1);
rep(j,l,r){
int val=cnt[n+1+(j-l)];
b[j]=(b[j]+val)%mod;
}
}
// rep(i,1,n) printf("%lld\n",b[i]);
rep(i,1,n){
// printf("b[i]=%d\n",b[i]);
IO.write_int(b[i]);
IO.write_char('\n');
}
return 0;
}
Zhengrui 2022ABDay1 A
其中
闵可夫斯基和裸题。显然函数
考虑如何合并,需要知道最左边和最右边两个区间是否都为
其余的合并都是平凡的。
int n,a[N];
vi v[N<<2][3][3],t[3][3];
#define ls(k) k<<1
#define rs(k) k<<1|1
inline void Merge(vi b,vi c,vi &d,int o){
int n=(int)b.size()-1,m=(int)c.size()-1;
for(int i=0,j=0;i<=n&&j<=m;){
cmax(d[i+j+o],b[i]+c[j]);
if(j==m||(i<n&&b[i+1]-b[i]>c[j+1]-c[j])) i++;
else j++;
}
}
inline void PushUp(int k){
rep(i,0,2)rep(j,0,2){
Merge(v[ls(k)][i][0],v[rs(k)][1][j],v[k][i][j],1);
Merge(v[ls(k)][i][1],v[rs(k)][0][j],v[k][i][j],1);
Merge(v[ls(k)][i][2],v[rs(k)][2][j],v[k][i][j],0);
}
}
inline void Divid(int k,int l,int r){
rep(i,0,2)rep(j,0,2) v[k][i][j].resize(r-l+1+1,-INF);
if(l==r){
v[k][2][2][0]=v[k][2][2][1]=0;
v[k][0][2][0]=v[k][2][0][0]=-a[l];
v[k][1][2][0]=v[k][2][1][0]=a[l];
return;
}
int mid=(l+r)>>1;
Divid(ls(k),l,mid);Divid(rs(k),mid+1,r);
rep(i,0,2)rep(j,0,2){
rep(o,0,mid-l+1) cmax(v[k][i][j][o],v[ls(k)][i][j][o]);
rep(o,0,r-mid) cmax(v[k][i][j][o],v[rs(k)][i][j][o]);
}
PushUp(k);
}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);rep(i,1,n) read(a[i]);
Divid(1,1,n);
rep(i,1,n){
printf("%lld\n",v[1][2][2][i]);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现