挖坑
总是要填的
可是我不填
哎呀真香!
水题1
既然是简单的题目,那当然是放大水题辣
只有a,b 的二进制的每一个1位置都不同时a&b ==0
所以随便维护一下每个数二进制有1位的序列最大值就行了QAQ
#include <iostream> #include <cstdio> using namespace std; const int N=100000+10; int a[N],dp[N],s[60],ans,n; void read(int &x){ x=0;int f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} x*=f; } int main(){ read(n); for(int i=1;i<=n;i++) read(a[i]); for(int i=1;i<=n;i++){ int x=a[i],mx=0,t=0; while(x){ ++t; if(x%2) mx=max(mx,s[t]); x/=2; } dp[i]=mx+1; x=a[i];t=0; while(x){ ++t; if(x%2) s[t]=max(s[t],dp[i]); x/=2; } ans=max(ans,dp[i]); } printf("%d",ans); return 0; }
既然是简单的题目,那当然是放大水题辣
正反hash,暴力枚举串o1判断
剪枝:ans*k如果大于n,显然不比当前答案更优
#include <iostream> #include <cstdio> #include <map> #define ull unsigned long long using namespace std; const int base=19260817; const int N=200000+10; int n,a[N]; ull b[N],hs1[N],hs2[N]; map<ull,bool>mp; //set<ull>se; void read(int &x){ x=0;int f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} x*=f; } void read(ull &x){ x=0;ull f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} x*=f; } int st[N],top; int main(){ read(n); for(register int i=1;i<=n;i++) read(a[i]); b[0]=1; for(register int i=1;i<=n;i++) b[i]=b[i-1]*base; for(register int i=1;i<=n;i++) hs1[i]=hs1[i-1]*base+a[i]; for(register int i=n;i;i--) hs2[i]=hs2[i+1]*base+a[i]; int ans=0; for(register int i=1;i<=n;i++){ int s=0; mp.clear(); ull h,f; for(register int j=i;j<=n;j+=i){ if(ans*i>n) break; h=hs1[j]-hs1[j-i]*b[i]; f=hs2[j-i+1]-hs2[j+1]*b[i]; // se.insert(h); // se.insert(f); // if(se.size()!=s) s++; // if(i==1) cout<<b[i]<<' '; if((!mp.count(h))&&(!mp.count(f))){ s++; mp[h]=mp[f]=1; } } if(s>ans){ ans=s; st[top=1]=i; } else if(s==ans) st[++top]=i; // if(i==2) cout<<s<<' } printf("%d %d ",ans,top); for(register int i=1;i<=top;i++) printf("%d ",st[i]); return 0; }
CDQ分治。。。
KD-Tree 应该也行
那个啥有一个小点忘记讲了QAQ
x和y的值都很大,如果用BIT维护x或y轴显然是不太优的
所以要把x或y离散化
#include <iostream> #include <cstdio> #include <algorithm> #include <map> #define ll long long using namespace std; const int N=2500000+10; ll n,m,ans[N],cnt,tot,bt[N*2]; map<ll,ll>mp; struct nod{ ll x,y,id,val,opt; bool operator < (const nod&a) const { return x<a.x; } }a[N]; struct tre{ ll x,y; bool operator < (const tre&a) const { return y<a.y; } }t[N]; void read(ll &x){ x=0;ll f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} x*=f; } ll lowbit(ll x){ return x&(-x); } void update(ll x,ll v){ for(ll i=x;i<=cnt;i+=lowbit(i)) bt[i]+=v; } ll query(ll x){ ll ans=0; for(ll i=x;i;i-=lowbit(i)) ans+=bt[i]; return ans; } nod q[N]; void cdq(ll l,ll r){ if(l==r) return ; ll mid=(l+r)/2; cdq(l,mid); cdq(mid+1,r); int qwq=l-1,l1=l,l2=(l+mid)/2+1,m1=(l+mid)/2; while(l1<=m1&&l2<=mid){ if(a[l2]<a[l1]) q[++qwq]=a[l2++]; else q[++qwq]=a[l1++]; } while(l1<=m1) q[++qwq]=a[l1++]; while(l2<=mid) q[++qwq]=a[l2++]; l1=mid+1;m1=(mid+1+r)/2;l2=m1+1; while(l1<=m1&&l2<=r){ if(a[l2]<a[l1]) q[++qwq]=a[l2++]; else q[++qwq]=a[l1++]; } while(l1<=m1) q[++qwq]=a[l1++]; while(l2<=r) q[++qwq]=a[l2++]; for(int i=l;i<=r;i++) a[i]=q[i]; ll j=l; for(ll i=mid+1;i<=r;i++){ for(;j<=mid&&a[j].x<=a[i].x;j++) if(!a[j].opt) update(a[j].y,a[j].val); // cout<<1; if(a[i].opt) ans[a[i].id]+=a[i].val*query(a[i].y); } for(ll i=l;i<j;i++) if(!a[i].opt) update(a[i].y,-a[i].val); } ll b[N],aa[N],bc; int main(){ // freopen("QAQQWQ.in","r",stdin); read(n);read(m); for(ll i=1;i<=n;i++) read(t[i].x),read(t[i].y); sort(t+1,t+1+n); aa[0]=-1; for(ll i=1;i<=n;i++) aa[++bc]=t[i].y+1; for(ll i=1;i<=n;i++) a[++tot]=(nod){t[i].x+1,t[i].y+1,0,1,0}; for(ll i=1;i<=m;i++){ ll x1,x2,y1,y2; read(x2);read(y2); read(x1);read(y1); ++x2;++x1;++y1;++y2; a[++tot]=(nod){x1,y1,i,1,1}; a[++tot]=(nod){x2-1,y2-1,i,1,1}; a[++tot]=(nod){x1,y2-1,i,-1,1}; a[++tot]=(nod){x2-1,y1,i,-1,1}; aa[++bc]=y1;aa[++bc]=y2-1; } sort(aa+1,aa+1+bc); for(ll i=1;i<=bc;i++) if(aa[i]!=aa[i-1]) b[++cnt]=aa[i],mp[aa[i]]=cnt; for(ll i=1;i<=tot;i++) a[i].y=mp[a[i].y]; cdq(1,tot); for(ll i=1;i<=m;i++) printf("%lld ",ans[i]); return 0; }
QAQ不会写...
容易发现有三种跳法 向两边往外跳 向内跳
会发现 这世上可以看成一棵树
于是答案变成了两个节点间的距离
很遗憾如果我们直接求lca是不可行的
不过我们可以考虑让一个节点爬到和另一节点同一深度处
这直接除出跳的深度
这样的话效率就大大提高了,gcd?
这样来看我们可以二分节点爬的深度来解决这个问题
应该是这样?
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; int a[5],b[5],v,ans; struct QAQ{ int a[5]; bool operator != (const QAQ&x) const { return !(x.a[3]==a[3]&&x.a[1]==a[1]&&x.a[2]==a[2]); } }; void read(int &x){ x=0;int f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} x*=f; } QAQ calc(int a[],int k){ QAQ ans; int t1=a[2]-a[1],t2=a[3]-a[2]; for(int i=1;i<=3;i++) ans.a[i]=a[i]; if(t1==t2) return ans; if(t1>t2){ int t=min(k,(t1-1)/t2); k-=t;v+=t; ans.a[2]-=t*t2; ans.a[3]-=t*t2; } else { int t=min(k,(t2-1)/t1); k-=t;v+=t; ans.a[2]+=t*t1; ans.a[1]+=t*t1; } if(k) return calc(ans.a,k); else return ans; } int main(){ for(int i=1;i<=3;i++) read(a[i]); for(int i=1;i<=3;i++) read(b[i]); sort(a+1,a+4);sort(b+1,b+4); QAQ t1=calc(a,1000000000);int b1=v;v=0; QAQ t2=calc(b,1000000000);int b2=v;v=0; if(t1!=t2){ printf("NO"); return 0; } else printf("YES "); if(b1>b2){ swap(b1,b2); swap(a,b); } ans=(b2-b1); t1=calc(b,ans); for(int i=1;i<=3;i++) b[i]=t1.a[i]; int l=0,r=b2; while(l<r){ int mid=(l+r)/2; if(calc(a,mid)!=calc(b,mid)) l=mid+1; else r=mid; } printf("%d",ans+2*r); return 0; }
直接链表trie
#include <iostream> #include <cstdio> #define ll long long using namespace std; const int N=5000000+10; int n,val[N],v[N],nxt[N],first[N],cnt,sz=1; ll ans; char w[N],c; void add(int a,int b,char c){ v[++cnt]=b; nxt[cnt]=first[a]; w[cnt]=c; first[a]=cnt; } void insert(){ c=getchar(); int u=0,t=1; while(c==' ') c=getchar(); for(int i=1;c!=' ';i++,c=getchar()){ u=0; for(int j=first[t];j;j=nxt[j]) if(w[j]==c){ u=v[j]; break; } if(!u) add(t,u=++sz,c); t=u; val[u]++; ans=max(ans,1ll*val[u]*1ll*i); } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) insert(); printf("%lld",ans); return 0; }
世上这就是个基环树森林
所以直接断边做树形dp
dp[x][0/1]表示不选或选x的最大值
dp[x][0]+=max{dp[son[x]][1],dp[son[x]][0]}
dp[x][1]+=max{dp[son[x]][0]}
#include <iostream> #include <cstdio> #define ll long long using namespace std; const int N=1000000+10; int v[N*2],nxt[N*2],first[N],cnt=1; int n,m,val[N]; ll ans,dp[N][2]; bool vis[N],fl[N*2],QAQ; void read(int &x){ x=0;int f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} x*=f; } void add(int a,int b){ v[++cnt]=b; nxt[cnt]=first[a]; first[a]=cnt; } int s,t; void dfs(int x,int y){ vis[x]=1; for(int i=first[x];i&&QAQ;i=nxt[i]){ if(v[i]==y) continue; if(vis[v[i]]){ fl[i]=fl[i^1]=1; s=x;t=v[i]; QAQ=0; break; } else dfs(v[i],x); } } void getdp(int x,int y,int qwq){ vis[x]=1; if(x==qwq) dp[x][1]=0ll; else dp[x][1]=(ll)val[x]; dp[x][0]=0ll; for(int i=first[x];i;i=nxt[i]){ if(y==v[i]||fl[i]) continue; getdp(v[i],x,qwq); dp[x][1]+=dp[v[i]][0]; dp[x][0]+=max(dp[v[i]][1],dp[v[i]][0]); } } int main(){ read(n); for(int i=1;i<=n;i++){ read(val[i]); int x; read(x); add(x,i); add(i,x); } for(int i=1;i<=n;i++){ if(vis[i]) continue; QAQ=1; ll mx=0; dfs(i,0); getdp(s,0,t); mx=max(dp[s][0],dp[s][1]); getdp(t,0,s); ans+=max(mx,max(dp[t][0],dp[t][1])); } printf("%lld",ans); return 0; }
太久没填坑了,就随便放几道水题吧qwq
随便推一下会发现 原式=∑nD=1 F(n/D,m/D)*G(D)
其中 F(n,m)=(1+n)*n-n*(2n+1)(n+1)/3+n*(n+m+1)(m-n)/2-(m-n)(1+n)*n/2
G(D)=∑k|D miu(k)*k
#include <iostream> #include <cstdio> using namespace std; #define ll long long const int N=2000000+10; const int mod1=1000000000+7; const int mod2=mod1+2; int g1[N],g2[N],pri[N],cnt; int inv2,inv3,inv4,inv6; bool isp[N]; void read(int &x){ x=0;int f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} x*=f; } void euler(){ g1[1]=g2[1]=1; isp[1]=1; for(int i=2;i<N;i++){ if(!isp[i]){ pri[++cnt]=i; g1[i]=((1-i)%mod1+mod1)%mod1; g2[i]=((1-i)%mod2+mod2)%mod2; } for(int j=1;j<=cnt&&i*pri[j]<N;j++){ isp[i*pri[j]]=1; if(i%pri[j]==0){ g1[i*pri[j]]=g1[i]; g2[i*pri[j]]=g2[i]; break; } g1[i*pri[j]]=1ll*g1[i]*g1[pri[j]]%mod1; g2[i*pri[j]]=1ll*g2[i]*g2[pri[j]]%mod2; } } for(int i=1;i<N;i++) g1[i]=(g1[i-1]+1ll*g1[i])%mod1; for(int i=1;i<N;i++) g2[i]=(g2[i-1]+1ll*g2[i])%mod2; } int f1(int n,int m){ return ((((((1ll*(1ll*(1+n)%mod1*n%mod1*n%mod1)-1ll*(1ll*(2*n+1)%mod1*n%mod1*(n+1)%mod1)*inv3%mod1)%mod1)+1ll*n*(n+m+1)%mod1*(m-n)%mod1*inv2%mod1)%mod1)-1ll*(m-n)*(1+n)%mod1*n%mod1*inv2%mod1)%mod1+mod1)%mod1; } int f2(int n,int m){ return ((((((1ll*(1ll*(1+n)%mod2*n%mod2*n%mod2)-1ll*(1ll*(2*n+1)%mod2*n%mod2*(n+1)%mod2)*inv6%mod2)%mod2)+1ll*n*(n+m+1)%mod2*(m-n)%mod2*inv4%mod2)%mod2)-1ll*(m-n)*(1+n)%mod2*n%mod2*inv4%mod2)%mod2+mod2)%mod2; } int main(){ inv2=500000004; inv3=333333336; inv4=500000005; inv6=666666673; euler(); int t; read(t); while(t--){ int n,m; read(n);read(m); if(n>m) swap(n,m); ll ans1=0,ans2=0; for(int l=1,r;l<=n;l=r+1){ r=min(n/(n/l),m/(m/l)); ans1=(ans1+1ll*f1(n/l,m/l)*(((1ll*g1[r]-g1[l-1])%mod1+mod1)%mod1)%mod1)%mod1; ans2=(ans2+1ll*f2(n/l,m/l)*(((1ll*g2[r]-g2[l-1])%mod2+mod2)%mod2)%mod2)%mod2; } printf("%lld %lld ",ans1,ans2); } return 0; }
【7/12】((๑°ㅁ°๑)ᵎᵎᵎ 怎么又多了