CSP模拟<反思>(50~?)
csp模拟50#
异或#
疑惑是不是只有我是数位dp
考虑一个数 1
的长度加 1,所以直接数位dp,
1
则
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=100;
int num[N];
int dp[N][N][2];
int solve(int pos,int len,int limit,int fk){
if(!pos) return len+1;
if(!limit && dp[pos][len][fk]!=-1) return dp[pos][len][fk];
int up;
if(limit) up=num[pos];
else up=1;
int ans=0;
for(int i=0;i<=up;i++){
int en;
if(i==1) en=len+1;
else en=0;
if(fk==1){
ans+=solve(pos-1,en,limit&(i==up),1);
continue;
}
ans+=solve(pos-1,en,limit&(i==up),0);
}
if(!limit) dp[pos][len][fk]=ans;
return ans;
}
signed main(){
int n;
scanf("%lld",&n);
memset(dp,-1,sizeof(dp));
n--;
int cnt=0;
while(n){
num[++cnt]=n&1;
n>>=1;
}
int ans=solve(cnt,0,1,1);
cout<<ans<<endl;
}
树#
首先需要明确的是,
考虑暴跳,此时
再考虑
查询的时候,对于散块直接暴力,整块分两种情况直接加就可以。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=3*1e5+10;
int head[N*2],ver[N*2],nex[N*2],tot=0;
int B1,B2;
int dep[N],id[N],cnt=0,size[N],d[N];
int pos[N],l[N],r[N],t;
int s[N],DS1[203][203][203],DS2[N][203];
int n,q;
void add(int x,int y){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
}
void dfs(int x,int fa){
dep[x]=dep[fa]+1;
id[x]=++cnt;
d[cnt]=dep[x];
size[x]=1;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fa) continue;
dfs(y,x);
size[x]+=size[y];
}
}
void change(int L,int R,int x,int k,int z,int y,int kk){
int p=pos[L],q=pos[R];
if(p==q){
for(int i=L;i<=R;i++) if(d[i]%x==k) s[i]+=z;
}
else{
for(int i=L;i<=r[p];i++) if(d[i]%x==k) s[i]+=z;
for(int i=l[q];i<=R;i++) if(d[i]%x==k) s[i]+=z;
if(x<=B2){
for(int i=p+1;i<=q-1;i++){
DS1[x][k][i]+=z;
}
}
else{
for(int i=kk;i<=n;i+=x){
DS2[i][p+1]+=z;DS2[i][q]-=z;
}
}
}
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(1,0);
B1=1500,B2=200;
t=n/B1;
for(int i=1;i<=n/B1;i++){
l[i]=(i-1)*B1+1;
r[i]=i*B1;
}
if(r[t]<n) t++,l[t]=r[t-1]+1,r[t]=n;
for(int i=1;i<=t;i++){
for(int j=l[i];j<=r[i];j++){
pos[j]=i;
}
}
for(int w=1;w<=q;w++){
int op,x,y,v,z;
scanf("%d",&op);
if(op==1){
scanf("%d%d%d%d",&v,&x,&y,&z);
change(id[v],id[v]+size[v]-1,x,(dep[v]+y)%x,z,y,(dep[v]+y));
}
else{
scanf("%d",&v);
int ans=s[id[v]];
for(int i=1;i<=B2;i++){
ans+=DS1[i][dep[v]%i][pos[id[v]]];
}
for(int i=1;i<=pos[id[v]];i++){
ans+=DS2[dep[v]][i];
}
printf("%d\n",ans);
}
}
}
2023NOIP A层联测8#
集合#
背包,求出每种数出现的次数,但是幂数很大,但是费马小定理,模数是质数,
点击查看代码
// ubsan: undefined
// accoders
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
inline __int128 read(){
__int128 x(0),f(1);char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return x*f;
}
void print(__int128 x) {
if(x<0)putchar('-'),x=-x;
if(x>9)print(x/10);
putchar(x%10+48);
}
unsigned long long f[205][20105];
int mgml(int x,unsigned long long p){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
signed main(){
// freopen("collection.in","r",stdin);
// freopen("collection.out","w",stdout);
int n;
scanf("%lld",&n);
int sum=0;
for(int i=1;i<=n;i++) sum=(sum+i)%mod;
f[1][1]=1,f[1][0]=1;
for(int i=2;i<=n;i++){
for(int j=0;j<=sum;j++){
f[i][j+i]=(f[i][j+i]+f[i-1][j])%(mod-1);
f[i][j]=(f[i][j]+f[i-1][j])%(mod-1);
}
}
int ans=1;
for(int i=1;i<=sum;i++){
ans=(ans*mgml(i,f[n][i])%mod)%mod;
}
printf("%lld",ans);
}
出租#
摩尔定理,任意一段区间
点击查看代码
// ubsan: undefined
// accoders
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=-1e9;
const int N=5*1e5+10;
int a[N];
int b[N];
struct seg{
int l,r,sum,ma,sl,sr;
}tr[N<<2];
int n,m,k,d;
void pushdown(int p){
tr[p].sum=tr[p*2].sum+tr[p*2+1].sum;
tr[p].sl=max(tr[p*2].sl,tr[p*2].sum+tr[p*2+1].sl);
tr[p].sr=max(tr[p*2+1].sr,tr[p*2+1].sum+tr[p*2].sr);
tr[p].ma=max(tr[p*2].ma,max(tr[p*2+1].ma,tr[p*2].sr+tr[p*2+1].sl));
}
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
if(l==r){
tr[p].sum=tr[p].ma=tr[p].sl=tr[p].sr=-k;
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushdown(p);
}
void change(int p,int wh,int v){
if(tr[p].l==tr[p].r){
tr[p].sum+=v;
tr[p].ma=tr[p].sl=tr[p].sr=tr[p].sum;
return;
}
int mid=(tr[p].l+tr[p].r)/2;
if(wh<=mid) change(p*2,wh,v);
else change(p*2+1,wh,v);
pushdown(p);
}
signed main(){
freopen("lantern.in","r",stdin);
freopen("lantern.out","w",stdout);
scanf("%lld%lld%lld%lld",&n,&m,&k,&d);
build(1,1,n);
for(int p=1;p<=m;p++){
int x,y;
scanf("%lld%lld",&x,&y);
change(1,x,y);
if(tr[1].ma>k*d) printf("NO\n");
else printf("YES\n");
}
}
跳棋#
设字符中的棋子个数为
考虑有不确定的,所以直接 dp。
设
然后第一维可以滚掉。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=505;
const int mod=1e9+7;
char s[N];
int f[2][N][N][3];
int C[N][N];
int n;
void init(){
C[0][0]=1;
for(int i=1;i<=n;i++){
C[i][0]=1;
for(int j=1;j<=i;j++){
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
}
}
signed main(){
freopen("checkers.in", "r", stdin);
freopen("checkers.out", "w", stdout);
scanf("%lld",&n);
scanf("%s",s+1);
int op=0;
f[0][0][0][0]=1;
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
for(int k=0;k<=i;k++){
if(s[i+1]=='0' || s[i+1]=='?'){
f[op^1][j][k+1][0]=(f[op^1][j][k+1][0]+f[op][j][k][0]+f[op][j][k][1])%mod;
}
if(s[i+1]=='1' || s[i+1]=='?'){
f[op^1][j][k][1]=(f[op^1][j][k][1]+f[op][j][k][0])%mod;
f[op^1][j+1][k][0]=(f[op^1][j+1][k][0]+f[op][j][k][1])%mod;
}
}
}
for(int j=0;j<=i;j++)
for(int k=0;k<=i;k++)
f[op][j][k][0]=f[op][j][k][1]=0;
op^=1;
}
init();
int ans=0;
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
if(i+j>n) break;
int w=C[i+j][j]*(f[op][i][j][0]+f[op][i][j][1])%mod;
ans=(ans+w)%mod;
}
}
printf("%lld",ans);
}
连通块#
树上dp,设
复杂度
点击查看代码
// ubsan: undefined
// accoders
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
const int inf=-9187201950435737472;
vector<int> s[N];
int k;
int n,m;
int a[N];
int f[N][45];
bool flat[N];
int rk[N];
int mp[45][45];
int ans=0;
struct asd{
int x,y;
}b[N];
void dfs(int x){
if(flat[x]) f[x][rk[x]]=a[x];
else f[x][0]=a[x];
for(int i=0;i<s[x].size();i++){
int y=s[x][i];
dfs(y);
}
if(!s[x].size()) return;
for(int i=0;i<s[x].size();i++){
int y=s[x][i];
if(!flat[y]){
int mx=inf;
for(int j=0;j<=k;j++) mx=max(mx,f[x][j]);
if(mx==inf) continue;
for(int j=0;j<=k;j++) f[x][j]=max(mx+f[y][j],f[x][j]);
}
else{
int mx=inf;
for(int j=0;j<=k;j++) if(!mp[rk[y]][j]) mx=max(mx,f[x][j]);
if(mx==inf) continue;
for(int j=0;j<=k;j++) f[x][j]=max(mx+f[y][j],f[x][j]);
}
}
for(int i=0;i<=k;i++) ans=max(ans,f[x][i]);
}
signed main(){
freopen("connection.in","r",stdin);
freopen("connection.out","w",stdout);
memset(f,128,sizeof(f));
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++){
int x,y;
scanf("%lld",&x);
for(int j=1;j<=x;j++){
scanf("%lld",&y);
s[i].push_back(y);
}
}
for(int i=1;i<=m;i++){
scanf("%lld%lld",&b[i].x,&b[i].y);
flat[b[i].x]=flat[b[i].y]=1;
}
k=0;
for(int i=1;i<=n;i++){
if(flat[i]) rk[i]=++k;
}
for(int i=1;i<=m;i++){
int x=rk[b[i].x],y=rk[b[i].y];
mp[x][y]=mp[y][x]=1;
}
dfs(1);
printf("%lld",ans);
}
2023NOIP A层联测9#
挂分记 T1(40)+T4(40)
紫罗兰#
为啥我考场想矩阵,其实是一个
点击查看代码
// ubsan: undefined
// accoders
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=6002;
int n,m;
int head[N*2],ver[N*2],nex[N*2],tot=0;
int d[N];
void add(int x,int y){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
}
int ans=(1<<20);
int sum[N];
queue<int> q;
int num[N];
void bfs(int x){
q.push(x);
memset(d,-1,sizeof(d));
memset(num,0,sizeof(num));
d[x]=0;
num[x]=1;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(d[y]!=-1 && d[y]<d[x]) continue;
if(d[y]==-1){
d[y]=d[x]+1;
q.push(y);
}
else{
sum[d[x]+d[y]+1]+=num[y];
ans=min(ans,d[x]+d[y]+1);
}
if(d[y]==d[x]+1) num[y]++;
}
}
}
signed main(){
// freopen("B.in","r",stdin);
// freopen("B.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%lld%lld",&x,&y);
add(x,y),add(y,x);
}
for(int i=1;i<=n;i++){
bfs(i);
}
int cnt=sum[ans];
if(ans%2==0){
cnt=cnt/ans;
}
else{
cnt/=2;
cnt/=ans;
}
printf("%lld",cnt);
}
风信子#
超级钢琴+线段树(k=1)
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
struct seg{
int l,r,mx,mn,x,y;
int pmx,pmn;
int lazy;
int ans;
}tr[N*4];
struct asd{
int l,r,ls,rs,x,y,ans;
friend bool operator <(asd a,asd b){
return a.ans<b.ans;
}
};
priority_queue<asd> q;
void pushdown(int p){
if(tr[p].lazy){
tr[p*2].lazy+=tr[p].lazy;
tr[p*2+1].lazy+=tr[p].lazy;
tr[p*2].mx+=tr[p].lazy;
tr[p*2].mn+=tr[p].lazy;
tr[p*2+1].mx+=tr[p].lazy;
tr[p*2+1].mn+=tr[p].lazy;
tr[p].lazy=0;
}
}
seg pushup(seg a,seg b){
seg c;
c.lazy=0;
c.l=a.l,c.r=b.r;
if(a.mx>b.mx) c.mx=a.mx,c.pmx=a.pmx;
else c.mx=b.mx,c.pmx=b.pmx;
if(a.mn<b.mn) c.mn=a.mn,c.pmn=a.pmn;
else c.mn=b.mn,c.pmn=b.pmn;
c.ans=a.ans;
c.x=a.x,c.y=a.y;
if(b.ans>c.ans){
c.ans=b.ans;
c.x=b.x,c.y=b.y;
}
if(a.mx-b.mn>c.ans){
c.ans=a.mx-b.mn;
c.x=a.pmx,c.y=b.pmn;
}
return c;
}
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
tr[p].lazy=0;
if(l==r){
tr[p].mx=tr[p].mn=a[l];
tr[p].pmx=tr[p].pmn=l;
tr[p].x=tr[p].y=l;
tr[p].ans=0;
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
tr[p]=pushup(tr[p*2],tr[p*2+1]);
}
void change(int p,int l,int r,int v){
if(tr[p].l>=l && tr[p].r<=r){
tr[p].lazy+=v;
tr[p].mn+=v,tr[p].mx+=v;
return;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
if(l<=mid) change(p*2,l,r,v);
if(r>mid) change(p*2+1,l,r,v);
tr[p]=pushup(tr[p*2],tr[p*2+1]);
}
seg ask(int p,int l,int r){
if(tr[p].l>=l && tr[p].r<=r){
return tr[p];
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
seg ls,rs;
ls.l=ls.r=0;
rs.l=rs.r=0;
if(l<=mid) ls=ask(p*2,l,r);
if(r>mid) rs=ask(p*2+1,l,r);
if(ls.l==0) return rs;
else if(rs.l==0) return ls;
else return pushup(ls,rs);
}
void split_A(int l,int r){
seg qw=ask(1,l,r);
asd a;
a.l=a.ls=l,a.r=a.rs=r;
a.ans=qw.ans;
a.x=qw.x,a.y=qw.y;
q.push(a);
}
void split_B(int l,int r,int ls,int rs){
seg qw=ask(1,l,r);
seg we=ask(1,ls,rs);
asd a;
a.l=l,a.r=r;
a.ls=ls,a.rs=rs;
a.ans=qw.mx-we.mn;
a.x=qw.pmx,a.y=we.pmn;
q.push(a);
}
int query(int L,int R,int k){
int ans=0;
while(!q.empty()) q.pop();
split_A(L,R);
while(k--){
asd a=q.top();
q.pop();
ans+=a.ans;
int l=a.l,r=a.r,x=a.x,y=a.y;
int ls=a.ls,rs=a.rs;
if(l==ls){
if(x>l) split_A(l,x-1);
if(x>l) split_B(l,x-1,x,r);
if(x!=y) split_A(x,x);
if(x<y-1) split_B(x,x,x+1,y-1);
if(y<r) split_B(x,x,y+1,r);
if(x<r) split_A(x+1,r);
}
else{
if(x>l) split_B(l,x-1,ls,rs);
if(ls<y) split_B(x,x,ls,y-1);
if(y<rs) split_B(x,x,y+1,rs);
if(x<r) split_B(x+1,r,ls,rs);
}
}
return ans;
}
signed main(){
freopen("D.in","r",stdin);
freopen("D.out","w",stdout);
int n,m;
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
for(int i=1;i<=m;i++){
int op,l,r,x;
scanf("%lld%lld%lld%lld",&op,&l,&r,&x);
if(op==1) change(1,l,r,x);
else{
int ans=query(l,r,x);
printf("%lld\n",ans);
}
}
}
CSP模拟57联测19 _2023NOIP A层联测12#
醉#
直径的性质,所以在树上离一个点最远的点一定出于直径之一,所以倍增跳就可以。
与#
判断时,枚举
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3*1e5+10;
int a[N];
int f[N][50];
int dp[N][50];
signed main(){
freopen("and.in","r",stdin);
freopen("and.out","w",stdout);
int n,q;
scanf("%lld%lld",&n,&q);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++){
for(int j=1;j<=20;j++){
f[i][j]=f[i-1][j];
if(a[i-1]&(1ll<<(j-1))){
f[i][j]=max(f[i][j],i-1);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=20;j++){
if(a[i]&(1ll<<(j-1))) dp[i][j]=max(dp[i][j],f[i][j]);
for(int k=1;k<=20;k++){
if(a[i]&(1ll<<(k-1))){
dp[i][j]=max(dp[i][j],dp[f[i][k]][j]);
}
}
}
}
for(int i=1;i<=q;i++){
int x,y;
scanf("%lld%lld",&x,&y);
int getans=0;
for(int j=1;j<=20;j++){
if(a[x]&(1ll<<(j-1))){
if(dp[y][j]>=x) getans=1;
}
if(getans) break;
}
if(getans) printf("Shi\n");
else printf("Fou\n");
}
}
小恐龙#
对于每个塔有一个时间限制
如果要求一个区间内的点从一定时间从零开始回复的值,用主席树维护前缀和,相当于二维偏序,对于小于
点击查看代码
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2*1e5+10;
struct tree{
int l,r,cs,rs;
}tr[N*32],ans;
struct qwe{
int cs,rs;
};
int cs[N],rs[N];
int rt[N],tot=0;
void build(int &p,int l,int r){
p=++tot;
tr[p].cs=tr[p].rs=0;
if(l==r) return;
int mid=(l+r)/2;
build(tr[p].l,l,mid);
build(tr[p].r,mid+1,r);
}
void change(int p,int &now,int wh,int v,int l,int r){
now=++tot;
tr[now]=tr[p];
if(l==r){
tr[now].cs+=cs[v];
tr[now].rs+=rs[v];
return;
}
int mid=(l+r)>>1;
if(wh<=mid) change(tr[p].l,tr[now].l,wh,v,l,mid);
else change(tr[p].r,tr[now].r,wh,v,mid+1,r);
tr[now].cs=tr[tr[now].l].cs+tr[tr[now].r].cs;
tr[now].rs=tr[tr[now].l].rs+tr[tr[now].r].rs;
return;
}
void ask(int p1,int p2,int l,int r,int ls,int rs){
if(ls>rs) return;
if(ls<=l && r<=rs){
ans.cs=ans.cs+tr[p2].cs-tr[p1].cs;
ans.rs=ans.rs+tr[p2].rs-tr[p1].rs;
return;
}
int mid=(l+r)>>1;
if(ls<=mid) ask(tr[p1].l,tr[p2].l,l,mid,ls,rs);
if(rs>mid) ask(tr[p1].r,tr[p2].r,mid+1,r,ls,rs);
return;
}
struct zxc{
int l,r,typ,t;
}st[N];
// tpy 1: 有值
// tpy 0: 空
struct asd{
double ls;
int id;
}a[N];
double uu[N];
bool amp(asd a,asd b){
return a.ls<b.ls;
}
int rk[N];
int ms[N];
inline int read(){
int x(0);bool f(0);char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) f^=ch=='-';
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return f?x=-x:x;
}
signed main(){
freopen("dinosaurs.in","r",stdin);
freopen("dinosaurs.out","w",stdout);
int n;
scanf("%lld",&n);
int sum=0;
for(int i=1;i<=n;i++){
cs[i]=read(),rs[i]=read();
ms[i]=cs[i];
sum+=cs[i];
a[i].ls=1.0*cs[i]/(1.0*rs[i]);
a[i].id=i;
}
sort(a+1,a+n+1,amp);
for(int i=1;i<=n;i++){
uu[i]=a[i].ls;
rk[a[i].id]=i;
}
for(int i=1;i<=n;i++) change(rt[i-1],rt[i],rk[i],i,0,n);
int head=1,tail=0;
for(int i=1;i<=n;++i){
st[++tail]={i,i,1,0};
}
int cnt=0;
int q;
scanf("%lld",&q);
while(q--){
int T,h;
T=read(),h=read();
for(int i=head;i<=tail;++i){
zxc s=st[i];
int t=s.t,l=s.l,r=s.r;
if(s.typ==1){
ms[l]=min(cs[l],ms[l]+rs[r]*(T-t));
if(ms[l]==h){
h=0;
st[i]={1,l,0,T};
head=i;
ms[l]=0;
break;
}
if(h>ms[l]) h-=ms[l];
else{
ms[l]-=h;
h=0;
if(i==head) st[i]={l,r,1,T};
else{
st[i]={l,r,1,T};
st[i-1]={1,l-1,0,T};
head=i-1;
}
break;
}
}
else{
int ls=l,rs=r;
int anss=0;
int ts=lower_bound(uu+1,uu+n+1,T-t)-uu;
int sum=0;
ans.cs=ans.rs=0;ask(rt[l-1],rt[r],0,n,0,ts-1);
sum=ans.cs+sum;
ans.cs=ans.rs=0;ask(rt[l-1],rt[r],0,n,ts,n);
sum=ans.rs*(T-t)+sum;
if(h>sum){
h-=sum;
continue;
}
while(ls<=rs){
int mid=(ls+rs)/2;
int w=0;
ans.cs=ans.rs=0;ask(rt[l-1],rt[mid],0,n,0,ts-1);
w=ans.cs+w;
ans.cs=ans.rs=0;ask(rt[l-1],rt[mid],0,n,ts,n);
w=ans.rs*(T-t)+w;
if(w>=h){
anss=mid;
sum=w;
rs=mid-1;
}
else ls=mid+1;
}
int w=0;
w=sum;
w-=h;
h=0;
ms[anss]=w;
if(anss==r){
st[i]={anss,anss,1,T};
st[i-1]={1,anss-1,0,T};
head=i-1;
}
else{
st[i]={anss+1,r,0,t};
st[i-1]={anss,anss,1,T};
st[i-2]={1,anss-1,0,T};
head=i-2;
}
break;
}
}
if(h>0){
cnt+=h;
st[tail]={1,n,0,T};
head=tail;
}
}
// cerr<<" h ";
printf("%lld",cnt);
}
/*
2012071806018
2012085820295
2103386905648
2103486301372
2095554685252
2109804643826
2110010532227
2162578051794
2162359988216
2162536990636
2162583801592
*/
CSP模拟57联测19 2023NOIP A层联测13#
传话游戏#
烂,哈希被卡
全球覆盖#
横纵可以分开,而且计算起来是一样的。
所以考虑横,对于关键点之间每一段线段,可以唯一对应全部点对的方案,然后求一个每种方案线段之和最大值
所以考虑排个序,从左到右,然后异或
用
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
const int mod=998244353;
struct asd{
int x1,y1,x2,y2;
}a[N];
struct qwe{
int x,id,op;
}b[N],c[N];
int n,X,Y;
int mgml(int x,int p){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
unordered_map<int,int>mp;
bool amp(qwe a,qwe b){
return a.x<b.x;
}
mt19937_64 mt(clock());
int rnd[N];
signed main(){
freopen("globe.in","r",stdin);
freopen("globe.out","w",stdout);
scanf("%lld%lld%lld",&n,&X,&Y);
int cnt1=0,cnt2=0;
for(int i=1;i<=n;i++){
scanf("%lld%lld%lld%lld",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
b[++cnt1]={min(a[i].x1,a[i].x2),i,1};b[++cnt1]={max(a[i].x1,a[i].x2),i,0};
c[++cnt2]={min(a[i].y1,a[i].y2),i,1};c[++cnt2]={max(a[i].y1,a[i].y2),i,0};
}
for(int i=1;i<=n;i++) rnd[i]=mt();
sort(b+1,b+cnt1+1,amp);
sort(c+1,c+cnt2+1,amp);
int mx=0;
int zt=0;
for(int i=1;i<=cnt1;i++){
mp[zt]+=(b[i].x-b[i-1].x);
mx=max(mx,mp[zt]);
zt=zt^rnd[b[i].id];
}
mp[zt]+=(X-b[cnt1].x);
mx=max(mx,mp[zt]);
int my=0;
zt=0;
mp.clear();
for(int i=1;i<=cnt2;i++){
mp[zt]+=(c[i].x-c[i-1].x);
my=max(my,mp[zt]);
zt=zt^rnd[c[i].id];
}
mp[zt]+=(Y-c[cnt2].x);
my=max(my,mp[zt]);
cout<<mx*my;
}
幂次序列#
点分治,先扫一边,将和维护到一个桶里,然后再扫另一边时在桶里查询,维护一个最高位,设为
点击查看代码
// ubsan: undefined
// accoders
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2*1e5+10;
const int mod1=998244353;
const int mod2=1e9+3579;
int a[N];
map<pair<int,int>,int> mp1;
map<pair<int,int>,int> mp2;
int ans=0;
int ha[N],hb[N];
int ma[N],mb[N];
inline int mgml(int x,int p,int mod){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
map<int,int> vi;
void solve(int l,int r){
if(l==r){
ans++;
return;
}
int mid=(l+r)/2;
int sum1=0,sum2=0;
int ma=0;
mp1.clear(),mp2.clear();
vi.clear();
for(int i=mid;i>=l;--i){
sum1=(sum1+ha[i])%mod1;
sum2=(sum2+hb[i])%mod2;
int tmp=a[i];
while(vi[tmp]){
vi[tmp]=0;
tmp++;
}
vi[tmp]=1;
ma=max(tmp,ma);
mp1[make_pair(sum1,sum2)]++;
int w1=(mgml(2,ma+1,mod1)-sum1+mod1)%mod1;
int w2=(mgml(2,ma+1,mod2)-sum2+mod2)%mod2;
if(w1==sum1 && w2==sum2) continue;
mp2[make_pair(w1,w2)]++;
}
sum1=0,sum2=0;
int cnt=0;
ma=0;
vi.clear();
for(int i=mid+1;i<=r;++i){
sum1=(sum1+ha[i])%mod1;
sum2=(sum2+hb[i])%mod2;
int tmp=a[i];
while(vi[tmp]){
vi[tmp]=0;
tmp++;
}
vi[tmp]=1;
ma=max(ma,tmp);
int w1=(mgml(2,ma+1,mod1)-sum1+mod1)%mod1;
int w2=(mgml(2,ma+1,mod2)-sum2+mod2)%mod2;
cnt+=mp1[make_pair(w1,w2)];
cnt+=mp2[make_pair(sum1,sum2)];
}
ans+=cnt;
solve(l,mid),solve(mid+1,r);
}
inline int read(){
int x(0);bool f(0);char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) f^=ch=='-';
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return f?x=-x:x;
}
signed main(){
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
int n;
n=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i){
ha[i]=mgml(2,a[i],mod1);
hb[i]=mgml(2,a[i],mod2);
}
solve(1,n);
printf("%lld",ans);
}
CSP模拟58联测20#
正睿=罚坐
回忆旅途的过往#
因为只有
考场主要是如何快速求出是否可以表示没想到,实际上是预处理,设
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
const int M=1e5+10;
int a[N];
int st[20];
bool f[2050][M];
struct asd{
int op,l,r,x;
}b[N];
int rk[N];
struct tree{
int l,r,zt;
int lazy;
}tr[N*4];
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
tr[p].lazy=0;
if(l==r){
tr[p].zt=(1<<(rk[a[l]]-1));
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
tr[p].zt=tr[p*2].zt|tr[p*2+1].zt;
}
void pushdown(int p){
if(tr[p].lazy){
tr[p*2].lazy=tr[p].lazy;
tr[p*2+1].lazy=tr[p].lazy;
tr[p*2].zt=tr[p].lazy;
tr[p*2+1].zt=tr[p].lazy;
tr[p].lazy=0;
}
}
void change(int p,int l,int r,int v){
if(tr[p].l>=l && tr[p].r<=r){
tr[p].zt=(1<<(rk[v]-1));
tr[p].lazy=(1<<(rk[v]-1));
return;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
if(l<=mid) change(p*2,l,r,v);
if(r>mid) change(p*2+1,l,r,v);
tr[p].zt=tr[p*2].zt|tr[p*2+1].zt;
}
int ask(int p,int l,int r){
if(tr[p].l>=l && tr[p].r<=r) return tr[p].zt;
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
int ans=0;
if(l<=mid) ans=ans|ask(p*2,l,r);
if(r>mid) ans=ans|ask(p*2+1,l,r);
return ans;
}
signed main(){
// freopen("past3.in","r",stdin);
// freopen("1.out","w",stdout);
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
int top=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(rk[a[i]]==0){
st[++top]=a[i];
rk[a[i]]=top;
}
}
int ma=0;
for(int i=1;i<=q;i++){
scanf("%d%d%d%d",&b[i].op,&b[i].l,&b[i].r,&b[i].x);
if(b[i].op==1){
if(rk[b[i].x]==0){
st[++top]=b[i].x;
rk[b[i].x]=top;
}
}
else ma=max(ma,b[i].x);
}
build(1,1,n);
f[0][0]=1;
for(int i=0;i<top;i++){
int t=(1<<i);
for(int s=0;s<t;s++){
f[s][0]=1;
for(int k=0;k<=ma;k++) f[s+t][k]|=f[s][k];
for(int k=0;k<=ma-st[i+1];k++) f[s+t][k+st[i+1]]|=f[s+t][k];
}
}
for(int i=1;i<=q;i++){
if(b[i].op==1){
change(1,b[i].l,b[i].r,b[i].x);
}
if(b[i].op==2){
int s=ask(1,b[i].l,b[i].r);
if(f[s][b[i].x]) printf("Yes\n");
else printf("No\n");
}
}
}
/*
如何判断是否可行
可以用完全背包,但是复杂度炸裂
肯定枚举那十个数,然后判断是否在区间出现
如何判断可行,感觉就是背包,但是会有一些优化
比如当前点不行就终止
最外层是物品数量,然后是容量,最后是个数
判断可行直接枚举当前物品倍数判断,
*/
牵着她的手#
首先一个结论是的东西,前
等同于求
然后就是:拉格朗日插值。
就结束了。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
const int mod=1e9+7;
int n,m,k;
int fac[N*2+10],inv[N*2+10];
int y[N*2+10];
int mgml(int x,int p){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
signed main(){
int T;
scanf("%lld",&T);
fac[0]=1,inv[0]=1;
for(int i=1;i<=N*2;i++){
fac[i]=fac[i-1]*i%mod;
inv[i]=mgml(fac[i],mod-2);
}
while(T--){
scanf("%lld%lld%lld",&n,&m,&k);
int tmp=1;
for(int i=1;i<=n+m+2;i++) tmp=tmp*(k-i)%mod;
for(int i=1;i<=n+m+2;i++){
y[i]=(y[i-1]+(mgml(i,n)-mgml(i-1,n)+mod)*(mgml(i,m)-mgml(i-1,m)+mod)%mod)%mod;
}
int ans=0;
for(int i=1;i<=n+m+2;i++){
int w=y[i]*tmp%mod*mgml(k-i,mod-2)%mod*inv[i-1]%mod*inv[n+m+2-i]%mod;
if((n+m+2-i)%2) w=-w;
ans=(ans+w+mod)%mod;
}
if(k<=n+m+2) ans=y[k];
printf("%lld\n",ans);
}
}
/*
行与列是有关系的,所以列的最大值不可以超过行的最大值
正睿=罚坐
前后两半的最大值相等,剩下就没有限制了?
确实,所以是不是可以容斥
其实就是随便选的方案减去最大值不相等的方案
*/
注视一切的终结#
挺好一倍增,设
还有就是如果颜色大于
然后就是转移:
查询时转移也是类似的,不是一样的。
尽量不要用
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=5*1e5+2;
int head[N],ver[N*2],nex[N*2],tot=0;
unordered_map<int,int> rk[N];
inline void add(int x,int y){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
}
vector<int> s[N];
unordered_map<int,int> mp[N];
int f[N][21];
int dp[N][21][4][4];
int col[N][4];
int d[N];
int t;
int n,m;
void dfs(int x,int fa){
d[x]=d[fa]+1;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fa) continue;
f[y][0]=x;
int p=rk[x][y];
int len=s[p].size();
col[y][0]=min(3,len);
for(int j=1;j<=col[y][0];j++){
col[y][j]=s[p][j-1];
}
dfs(y,x);
}
}
void init(){
t=log2(n)+1;
for(int j=1;j<=t;++j)
for(int i=1;i<=n;++i)
f[i][j]=f[f[i][j-1]][j-1];
for(int x=1;x<=n;++x)
for(int j=1;j<=col[x][0];++j)
for(int k=1;k<=col[f[x][0]][0];++k)
dp[x][0][j][k]=(col[x][j]!=col[f[x][0]][k]);
for(int x=1;x<=n;++x){
for(int i=1;i<=t;++i){
int y=f[x][i-1],z=f[x][i];
for(int k1=1;k1<=col[x][0];++k1){
for(int k2=1;k2<=col[y][0];++k2){
for(int k3=1;k3<=col[z][0];++k3){
dp[x][i][k1][k3]=max(dp[x][i][k1][k3],dp[x][i-1][k1][k2]+dp[y][i-1][k2][k3]);
}
}
}
}
}
}
inline int ask_lca(int x,int y){
if(d[x]>d[y]) swap(x,y);
for(int i=t;i>=0;--i){
if(d[f[y][i]]>=d[x]) y=f[y][i];
}
if(x==y) return x;
for(int i=t;i>=0;--i){
if(f[x][i]!=f[y][i]){
x=f[x][i],y=f[y][i];
}
}
return f[x][0];
}
int cx[4],cy[4];
inline void solve1(int &x,int top){
memset(cx,0,sizeof(cx));
for(int i=t;i>=0;--i){
if(d[f[x][i]]>d[top]){
int y=f[x][i];
int cz[4];
memset(cz,0,sizeof(cz));
for(int k2=1;k2<=col[y][0];++k2){
for(int k1=1;k1<=col[x][0];++k1){
cz[k2]=max(cz[k2],cx[k1]+dp[x][i][k1][k2]);
}
}
for(int k2=1;k2<=col[y][0];++k2){
cx[k2]=cz[k2];
}
x=f[x][i];
}
}
return;
}
inline void solve2(int &x,int top){
memset(cy,0,sizeof(cy));
for(int i=t;i>=0;--i){
if(d[f[x][i]]>d[top]){
int y=f[x][i];
int cz[4];
memset(cz,0,sizeof(cz));
for(int k2=1;k2<=col[y][0];++k2){
for(int k1=1;k1<=col[x][0];++k1){
cz[k2]=max(cz[k2],cy[k1]+dp[x][i][k1][k2]);
}
}
for(int k2=1;k2<=col[y][0];++k2){
cy[k2]=cz[k2];
}
x=f[x][i];
}
}
return;
}
inline int read(){
int x(0);bool f(0);char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) f^=ch=='-';
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return f?x=-x:x;
}
inline void write(int x){
x<0?x=-x,putchar('-'):0;static short Sta[50],top(0);
do{Sta[++top]=x%10;x/=10;}while(x);
while(top) putchar(Sta[top--]|48);
putchar('\n');
}
signed main(){
n=read(),m=read();
int cnt=0;
for(int i=1;i<=m;++i){
int x,y,w;
x=read(),y=read(),w=read();
if(rk[x][y]==0){
cnt++;
rk[x][y]=cnt;
rk[y][x]=cnt;
add(x,y),add(y,x);
}
int p=rk[x][y];
if(mp[p][w]==0){
s[p].push_back(w);
mp[p][w]=1;
}
}
dfs(1,0);
init();
int q;
q=read();
while(q--){
int x,y;
x=read(),y=read();
if(x==y){
printf("0\n");
continue;
}
int lca=ask_lca(x,y);
int ans=0;
if(x!=lca) solve1(x,lca);
if(y!=lca) solve2(y,lca);
if(x==lca) for(int i=1;i<=col[y][0];++i) ans=max(ans,cy[i]);
else if(y==lca) for(int i=1;i<=col[x][0];++i) ans=max(ans,cx[i]);
else{
for(int i=1;i<=col[x][0];++i){
for(int j=1;j<=col[y][0];++j){
ans=max(ans,cx[i]+cy[j]+(col[x][i]!=col[y][j]));
}
}
}
write(ans);
}
}
作者:bloss
出处:https://www.cnblogs.com/jinjiaqioi/p/17747963.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】