CSP模拟<反思>(35~41)
好久没有写博客了
csp模拟35#
斯坦纳树#
错误做法会使
倒序删除一些点,假如这个点分叉数大于等于3 ,则
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=6*1e5+5;
int head[N*2],ver[N*2],nex[N*2],tot=0;
void add(int x,int y){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
}
int du[N];
int x[N],y[N],w[N];
int b[N],a[N];
bool flat[N];
int fa[N],sum[N];
int get_fa(int x){
if(fa[x]==x) return fa[x];
else return fa[x]=get_fa(fa[x]);
}
map<int,int>mp[N];
int cnt=0;
bool vis[N];
void dele(int x){
if(du[x]==1){
if(flat[x]){
flat[x]=0;
cnt--;
}
du[x]=0;
vis[x]=0;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(!vis[y]) continue;
du[y]--;
if(flat[y]==1){
dele(y);
}
}
}
if(du[x]==2){
if(flat[x]){
flat[x]=0;
cnt--;
}
int la=0;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(!vis[y]) continue;
if(la){
add(la,y),add(y,la);
}
else la=y;
}
vis[x]=0;
du[x]=0;
}
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) fa[i]=i,sum[i]=1;
for(int i=1;i<n;i++){
scanf("%d%d%d",&x[i],&y[i],&w[i]);
if(w[i]==0){
int fx=get_fa(x[i]),fy=get_fa(y[i]);
if(fx!=fy){
fa[fx]=fy;
sum[fy]+=sum[fx];
}
}
}
for(int i=1;i<n;i++){
int fx=get_fa(x[i]),fy=get_fa(y[i]);
if(fx!=fy && mp[fx][fy]==0){
add(fx,fy),add(fy,fx);
vis[fx]=vis[fy]=1;
du[fx]++,du[fy]++;
mp[fx][fy]=mp[fy][fx]=1;
}
}
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
}
for(int k=n;k>=1;k--){
if(cnt==0) a[k]=1;
else a[k]=0;
int x=get_fa(b[k]);
if(sum[x]>1){
sum[x]--;
continue;
}
if(du[x]>=3){
flat[x]=1;
cnt++;
}
if(du[x]==2){
int la=0;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(!vis[y]) continue;
if(la){
add(la,y),add(y,la);
break;
}
else la=y;
}
vis[x]=0;
du[x]=0;
}
if(du[x]==1) dele(x);
}
for(int i=1;i<=n;i++){
cout<<a[i];
}
}
csp模拟36#
博弈#
首先结论是对于一段异或和为0,则先手必输,但是 1 ^ 2 ^ 3=0 所以用哈希,但我比较弱,瞎搞了一个。然后开一个桶树上求就可以了。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5*1e5+5;
const int M=8*1e6;
bool nprime[M];
int prime[M];
void get_prime(){
for(int i=2;i<=M-5;i++){
if(!nprime[i]){
prime[++prime[0]]=i;
}
for(int j=1;j<=prime[0]&&i*prime[j]<=M-5;j++){
int k=i*prime[j];
nprime[k]=1;
if(i%prime[j]==0) break;
}
}
}
int g[N];
struct asd{
int x,y,w;
}a[N];
int n;
int head[N*2],ver[N*2],nex[N*2],edge[N*2],tot=0;
map<int,int>mp;
int ans=0;
void add(int x,int y,int w){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot,edge[tot]=w;
}
int p[N];
void dfs(int x,int f){
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==f) continue;
p[y]=p[x]^edge[i];
if(p[y]==0) ans++;
ans+=mp[p[y]];
mp[p[y]]++;
dfs(y,x);
}
}
int C(int x,int y){
int w=1;
for(int i=x;i>=1;i--){
w*=i;
}
for(int i=y;i>=1;i--){
w/=i;
}
for(int i=x-y;i>=1;i--){
w/=i;
}
return w;
}
void clear(int x){
tot=0;
ans=0;
for(int i=1;i<=x;i++){
head[i]=0;
p[x]=0;
}
mp.clear();
}
signed main(){
get_prime();
int op1=prime[60],op2=prime[600],op3=prime[6000],op4=prime[10000];
for(int i=1;i<=N;i++){
if(i%4==1){
prime[i]*=op1;
}
else if(i%4==2){
prime[i]*=op2;
}
else if(i%4==3){
prime[i]*=op3;
}
else{
prime[i]*=op4;
}
}
int T;
scanf("%lld",&T);
while(T--){
scanf("%lld",&n);
for(int i=1;i<n;i++){
scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].w);
g[i]=a[i].w;
}
sort(g+1,g+n);
int tot=unique(g+1,g+n)-(g+1);
for(int i=1;i<n;i++){
int t=lower_bound(g+1,g+n,a[i].w)-g;
t++;
add(a[i].x,a[i].y,prime[t]);
add(a[i].y,a[i].x,prime[t]);
}
dfs(1,0);
ans=n*(n-1)/2-ans;
printf("%lld\n",ans);
clear(n);
}
}
跳跃#
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1005;
int dp[N],la[N],a[N],s[N];
int g[N],sum[N];
signed main(){
int T;
scanf("%lld",&T);
while(T--){
int n,k;
scanf("%lld%lld",&n,&k);
s[0]=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
s[i]=s[i-1]+a[i];
}
int wh=0,mi=0;
for(int i=1;i<=n;i++){
la[i]=wh;
sum[i]=s[i]-s[la[i]];
if(s[i]<mi){
mi=s[i];
wh=i;
}
// cout<<sum[i]<<endl;
}
memset(dp,0x7f,sizeof(dp));
//1120231587044294
//9187201950435737471
for(int i=1;i<=n;i++){
if(s[i]>=0){
dp[i]=1;
g[i]=s[i];
}
}
for(int i=2;i<=n;i++){
for(int j=1;j<=i;j++){
int x=dp[j];
int ne=s[i]-s[j];
if(g[j]+ne+sum[j]*2>=0){
if(dp[i]>dp[j]+2){
dp[i]=dp[j]+2;
g[i]=g[j]+ne+sum[j]*2;
}
else if(dp[i]==dp[j]+2 && g[j]+ne+sum[j]*2>g[i]){
g[i]=g[j]+ne+sum[j]*2;
}
continue;
}
if(sum[j]<=0) continue;
ne=-(ne+g[j]);
int cs=ne/sum[j];
if(ne%sum[j]) cs++;
if(cs%2){
int c=cs+1+dp[j];
int w=cs*sum[j]+sum[j]+s[i]-s[j];
if(dp[i]>c){
dp[i]=c;
g[i]=g[j]+w;
}
else if(dp[i]==c && g[j]+w>g[i]){
g[i]=g[j]+w;
}
}
else{
int c=cs+dp[j];
int w=cs*sum[j]+s[i]-s[j];
if(dp[i]>c){
dp[i]=c;
g[i]=g[j]+w;
}
else if(dp[i]==c && g[j]+w>g[i]){
g[i]=g[j]+w;
}
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
int s=k-dp[i];
if(s<0) continue;
int cnt=sum[i]*s+g[i];
ans=max(ans,cnt);
}
printf("%lld\n",ans);
}
}
大陆#
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=60002;
int head[N*2],ver[N],nex[N],tot=0;
void add(int x,int y){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
}
int n,B;
int f[N];
int sd[N],rk[N],cnt=0,st[N],top=0;
void dfs(int x,int fa){
int mem=top;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fa) continue;
dfs(y,x);
f[x]+=f[y];
if(f[x]>=B){
f[x]=0;
sd[++cnt]=x;
for(int j=mem+1;j<=top;j++){
rk[st[j]]=cnt;
}
top=mem;
}
}
st[++top]=x;
f[x]++;
if(f[x]>=B){
f[x]=0;
sd[++cnt]=x;
for(int j=mem;j<=top;j++){
rk[st[j]]=cnt;
}
top=mem;
}
}
int main(){
scanf("%d%d",&n,&B);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(1,0);
if(f[1]) {
for(int j=1;j<=top;j++){
rk[st[j]]=cnt;
}
}
printf("%d\n",cnt);
for(int i=1;i<=n;i++){
printf("%d ",rk[i]);
}
cout<<endl;
for(int i=1;i<=cnt;i++){
printf("%d ",sd[i]);
}
}
排列#
一个神奇的平衡树,对于循环移位直接分裂后互换再合并就可以,考虑他是否可行,维护
其他的更新正常,就是更新前要一些值。
我代码
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=120005;
int n;
struct tree{
int l,r,rnd,size,mn,mx,pmn,pmx,tag,data;
}tr[N];
int root,idx=0;
inline void newnode(int &p,int x){
p=++idx;
tr[p].l=tr[p].r=0;
tr[p].rnd=rand()*rand(),tr[p].size=1;
tr[p].tag=0;
tr[p].data=tr[p].mx=tr[p].mn=x;
tr[p].pmn=(1ll<<30);
tr[p].pmx=-(1ll<<30);
}
int ask_pmn(int p,int v){
if(!p) return (1ll<<20);
if(tr[tr[p].r].mx>v) return ask_pmn(tr[p].r,v);
else if(tr[p].data>v) return tr[p].data;
else return ask_pmn(tr[p].l,v);
}
int ask_pmx(int p,int v){
if(!p) return -(1ll<<20);
if(tr[tr[p].l].mn<v) return ask_pmx(tr[p].l,v);
else if(tr[p].data<v) return tr[p].data;
else return ask_pmx(tr[p].r,v);
}
inline void pushdown(int p){
if(!p) return;
tr[p].size=tr[tr[p].l].size+tr[tr[p].r].size+1;
tr[p].mx=max(tr[p].data,max(tr[tr[p].l].mx,tr[tr[p].r].mx));
tr[p].mn=min(tr[p].data,min(tr[tr[p].l].mn,tr[tr[p].r].mn));
tr[p].pmn=min(tr[tr[p].l].pmn,tr[tr[p].r].pmn);
tr[p].pmx=max(tr[tr[p].l].pmx,tr[tr[p].r].pmx);
tr[p].tag=0;
tr[p].tag=(tr[tr[p].l].tag | tr[tr[p].r].tag);
if(tr[tr[p].l].mn<tr[p].data && tr[p].data<tr[tr[p].r].mx) tr[p].tag=1;
if(tr[tr[p].l].pmn<tr[tr[p].r].mx) tr[p].tag=1;
if(tr[tr[p].l].mn<tr[tr[p].r].pmx) tr[p].tag=1;
if(tr[p].tag) return;
// tr[p].pmn=(1<<30),tr[p].pmx=-(1<<30);
int wh,v;
v=min(tr[tr[p].l].mn,tr[p].data);
if(tr[p].data>v) tr[p].pmn=min(tr[p].pmn,tr[p].data);
if(tr[p].r && tr[tr[p].r].mx>v){
wh=ask_pmn(tr[p].r,v);
tr[p].pmn=min(tr[p].pmn,wh);
}
v=max(tr[tr[p].r].mx,tr[p].data);
if(tr[p].data<v) tr[p].pmx=max(tr[p].pmx,tr[p].data);
if(tr[p].l && tr[tr[p].l].mn<v){
wh=ask_pmx(tr[p].l,v);
tr[p].pmx=max(tr[p].pmx,wh);
}
}
inline void split(int p,int v,int &x,int &y){
if(p==0){
x=0,y=0;return;
}
if(tr[tr[p].l].size+1<=v){
x=p;
int xi=0;
split(tr[p].r,v-tr[tr[p].l].size-1,xi,y);
tr[p].r=xi;
}
else{
y=p;
int yi=0;
split(tr[p].l,v,x,yi);
tr[p].l=yi;
}
pushdown(p);
}
inline int merge(int x,int y){
if(!x || !y) return x+y;
if(tr[x].rnd<tr[y].rnd){
tr[x].r=merge(tr[x].r,y);
pushdown(x);return x;
}
else{
tr[y].l=merge(x,tr[y].l);
pushdown(y);return y;
}
}
void insert(int v,int id){
int x,y,z;
split(root,id,x,y);
newnode(z,v);
root=merge(merge(x,z),y);
}
void work(int a,int b,int k){
int x,y,p,q;
split(root,b,p,q);
// cout<<tr[p].size<<endl;
split(p,b-k,y,p);
// cout<<tr[y].size<<endl;
split(y,a-1,x,y);
// cout<<tr[x].size<<' '<<tr[y].size<<' '<<tr[p].size<<' '<<tr[q].size<<endl;
root=merge(merge(x,p),merge(y,q));
}
signed main(){
scanf("%lld",&n);
int k=time(0);
srand(1694609429);
tr[0].size=tr[0].data=0;
tr[0].l=tr[0].r=0;
tr[0].mn=(1ll<<20);
tr[0].mx=-(1ll<<20);
tr[0].pmn=(1ll<<20);
tr[0].pmx=-(1ll<<20);
tr[0].rnd=rand()*rand();
tr[0].tag=0;
for(int i=1;i<=n;i++){
int x;
scanf("%lld",&x);
insert(x,i);
}
int q;
scanf("%lld",&q);
for(int i=1;i<=q;i++){
int x,y,k;
scanf("%lld%lld%lld",&x,&y,&k);
work(x,y,k);
// for(int j=1;j<=idx;j++) cout<<tr[j].data<<' '<<tr[j].l<<' '<<tr[j].r<<endl;
if(tr[root].tag) printf("YES\n");
else printf("NO\n");
}
// cout<<k<<endl;
}
/*
7
7 5 6 3 4 2 1
5
4 5 1
2 5 2
2 6 3
2 7 3
1 7 4
*/
csp模拟37#
喷泉#
每个数都是以一段连续区间存在,且每次修改会使区间减少,所以直接维护区间的值,左端点右端点。但是当
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct asd{
int x,l,r;
};
vector<asd> q,p;
signed main(){
int n,m;
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
q.push_back({i,i,i});
}
int gcd=1;
for(int i=1;i<=m;i++){
int k;
scanf("%lld",&k);
if(gcd%k==0) continue;
int la=0;
int l,r;
gcd=q[1].x;
for(int j=0;j<q.size();j++){
asd a=q[j];
int ans=a.x;
if(a.x%k) ans=k*(a.x/k+1);
if(la==0){
la=ans;
l=a.l;r=a.r;
continue;
}
if(ans==la){
r=a.r;
}
else{
gcd=__gcd(gcd,la);
p.push_back({la,l,r});
la=ans;
l=a.l,r=a.r;
}
}
if(la){
gcd=__gcd(gcd,la);
p.push_back({la,l,r});
}
q.clear();
for(int j=0;j<p.size();j++){
q.push_back(p[j]);
}
p.clear();
}
for(int i=0;i<q.size();i++){
asd a=q[i];
for(int j=a.l;j<=a.r;j++){
printf("%lld ",a.x);
}
}
}
/*
6 2
3 2
*/
佛怒火莲#
我解释一下最后的方程:首先
点击查看代码
#include<bits/stdc++.h>
#define ui unsigned int
#define N 10010
using namespace std;
struct NUM{
int a,b,bs;
}num[N];
bool cmp(NUM x,NUM y){
return x.b<y.b;
}
map<int,int>col;
inline int Rand(int k){
return rand()%k;
}
int n,k,tp;
ui f[N],ok[6];
ui po[35];
void init(){
srand(time(0));
po[0]=1;
for(int i=1;i<=31;i++) po[i]=po[i-1]*2;
for(int i=0;i<=31;i++){
if(i%2<1) ok[0]+=po[i];
if(i%4<2) ok[1]+=po[i];
if(i%8<4) ok[2]+=po[i];
if(i%16<8) ok[3]+=po[i];
if(i%32<16) ok[4]+=po[i];
}
}
bool check(int mid,int n){
f[0]=1;
int la=0;
for(int i=1;i<=n;i++){
while(num[i].b-num[la+1].b>=mid&&la+1<=n) la++;
int cols=col[num[i].a];
f[i]=f[i-1]|((f[la]&ok[cols])<<po[cols]);
}
if(f[n]&po[po[k]-1]) return 1;
return 0;
}
int main(){
init();
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&k,&tp);
for(int i=1;i<=n;i++) scanf("%d%d",&num[i].a,&num[i].b);
sort(num+1,num+n+1,cmp);
int ans=0;
for(int ps=1;ps<=200;ps++){
col.clear();
for(int i=1;i<=n;i++)
if(col.find(num[i].a)==col.end()) col[num[i].a]=Rand(k);
int l=1,r=num[n].b,lans=1;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid,n)) lans=mid,l=mid+1;
else r=mid-1;
}
ans=max(ans,lans);
}
printf("%d\n",ans);
}
}
csp模拟38#
我是A题#
真是服了,好好一个题怎么恶心的时间空间,自家oj的评测机真是欠修理。
考虑
点击查看代码
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include<bits/stdc++.h>
#define max(x,y) (x)>(y)?(x):(y)
#define rg register
using namespace std;
const int N = 3e7 + 1;
typedef unsigned long long ull;
int n, A, B, C;
struct asd{
int x,y,z;
}a[N];
inline ull Rand (rg ull &k1, rg ull &k2) {
ull k3 = k1, k4 = k2;
k1 = k4;
k3 ^= (k3 << 23);
k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
return k2 + k4;
}
inline void print(__int128 x){
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10+48);
}
inline bool amp(const asd &a,const asd &b){
return a.z>b.z;
}
inline int Mod(ull x,int p){
return x<p?x:x%p;
}
void GetData () {
ull x, y;
scanf("%d%d%d%d%llu%llu",&n,&A,&B,&C,&x,&y);
for (int i = 1; i <= n; ++i) {
a[i].x = Mod(Rand(x, y) , A) + 1;
a[i].y = Mod(Rand(x, y) , B) + 1;
a[i].z = Mod(Rand(x, y) , C) + 1;
if (Rand(x, y) % 3 == 0) a[i].x = A;
if (Rand(x, y) % 3 == 0) a[i].y = B;
if ((a[i].x != A) && (a[i].y != B)) a[i].z = C;
}
}
int ma[N];
__int128 sma[N];
int mb[N];
__int128 smb[N];
int la[N],lb[N];
signed main(){
GetData();
__int128 r=1;//r*
rg int h=a[1].z;
rg int tp=0;
for(rg int i=1;i<=n;++i){
h=max(h,a[i].z);
if(a[i].x==A) lb[a[i].z]=max(lb[a[i].z],a[i].y);
if(a[i].y==B) la[a[i].z]=max(la[a[i].z],a[i].x);
}
for(int i=1;i<=n;i++){
if(a[i].z==h){
ma[a[i].x]=max(ma[a[i].x],a[i].y);
mb[a[i].y]=max(mb[a[i].y],a[i].x);
}
}
__int128 ans=0;
__int128 sma1=0;
for(rg int i=A;i;--i){
ma[i]=max(ma[i],ma[i+1]);
sma1=sma1+r*ma[i];
}
for(rg int i=B;i;--i){
mb[i]=max(mb[i],mb[i+1]);
}
__int128 sma=0,smb=0;
ans+=r*A*B-sma1;
rg int sa=0,sb=0;
for(rg int i=h-1;i;--i){
if(sa<=la[i]){
for(int j=sa+1;j<=la[i];j++){
sma=sma+r*ma[j];
}
sa=la[i];
}
if(sb<=lb[i]){
for(int j=sb+1;j<=lb[i];j++){
smb=smb+r*mb[j];
}
sb=lb[i];
}
__int128 op;
if(sb==0) op=1;
else op=sb;
if(mb[op]<sa){
ans+=r*(A-sa)*(B-sb);
}
else{
__int128 s1=r*A*sb-smb;//(smb[1]-smb[sb+1]);
__int128 s2=r*B*sa-sma;//(sma[1]-sma[sa+1]);
ans+=r*A*B-sma1-s1-s2;
}
}
__int128 uk=r*A*B*C-ans-r*A*B*(C-h);
print(uk);
}
/*
100 99 98 97 114514 1919810
2 10 10 10 114514 1919810
1000 43112 88371 27391 114514 1919810
104349748515623
9 7 10
7 10 3
*/
我是B题#
考试只会状压。
设
这里采用刷表法好写一点:
枚举质量为
初始值
转移方程:
答案
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int mgml(int x,int p){
x=(x+mod)%mod;
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
int dp[305][305];
int p[305];
int n;
int work(int d){
memset(dp,0,sizeof(dp));
dp[0][d-1]=1;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(dp[i][j]==0) continue;
dp[i+1][j]+=dp[i][j]*mgml(1-p[i+1],j+1)%mod;
dp[i+1][j]%=mod;
if(j>0) dp[i+1][j-1]+=(dp[i][j]*(1-mgml(1-p[i+1],j)+mod)%mod)%mod;
if(j>0) dp[i+1][j-1]%=mod;
}
}
return dp[n-1][0];
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<n;i++){
scanf("%lld",&p[i]);
}
int ans=0;
for(int i=1;i<=n;i++){
int d=work(i);
ans+=i*d%mod;
ans%=mod;
}
printf("%lld",ans);
}
我是C题#
首先一次找出所有出现次数较小的数字比较耗时,我们可以找到任意一个出现次数不满足要求的数字,并且从这个数字处把区间分成两半进行递归,并不会影响正确性,还大大降低了编程复杂度。
但是由于分治两边可能不均等,会导致时间复杂度退化成
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int a[N],b[N];
int cnt[N],d[N];
int ans=0;
void solve(int l,int r){
if(r-l+1<b[r-l+1]){
for(int i=l;i<=r;i++){
cnt[a[i]]--;
}
return;
}
if(l==r){
if(b[1]<=1) ans=max(ans,ans);
cnt[a[l]]--;
return;
}
int mid=(l+r)/2;
int pos=-1,k=b[r-l+1];
for(int i=l;i<=r;i++){
if(cnt[a[i]]<k){
pos=i;
break;
}
}
if(pos==-1){
for(int i=l;i<=r;i++) cnt[a[i]]--;
ans=max(ans,r-l+1);
return;
}
if(pos<=mid){
for(int i=l;i<=pos;i++) cnt[a[i]]--;
solve(pos+1,r);
for(int i=l;i<pos;i++) cnt[a[i]]++;
solve(l,pos-1);
}
else{
for(int i=pos;i<=r;i++) cnt[a[i]]--;
solve(l,pos-1);
for(int i=pos+1;i<=r;i++) cnt[a[i]]++;
solve(pos+1,r);
}
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
cnt[a[i]]++;
}
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
}
solve(1,n);
cout<<ans<<endl;
}
csp模拟39#
钱仓#
考虑起点是不是可以求出,每一个合法的情况的值都是固定的吗?(谁理解给我讲讲,反正我没听),起点为最大子段和的起点。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3*1e5+5;
int n;
int a[N];
int b[N];
long long ans=(1ll<<50);
int st[N];
long long check(int x){
int k=0;
for(int i=x;i<=x+n-1;i++){
b[i-x+1]=a[i];
k+=a[i];
if(k<i-x+1) return (1ll<<50);
}
long long sum=0;
int head=0,tail=0;
for(int i=n;i>=1;i--){
if(b[i]==0) st[++tail]=i;
else{
int tmp=b[i];
while(tmp && head+1<=tail){
int wh=++head;
sum+=(st[head]-i)*(st[head]-i);
tmp--;
}
if(tmp>1) return (1ll<<50);
if(tmp==0) st[++tail]=i;
}
}
return sum;
}
int sum[N];
signed main(){
freopen("barn.in","r",stdin);
freopen("barn.out","w",stdout);
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
a[n+i]=a[i];
sum[i]=sum[i-1]+a[i]-1;
}
for(int i=n+1;i<=n*2;i++){
sum[i]=sum[i-1]+a[i]-1;
}
int ma=-1;
int id=0,st;
for(int i=1;i<=n*2;i++){
if(sum[i]-sum[id]>=ma){
st=id;
ma=sum[i]-sum[id];
}
if(sum[id]>=sum[i] && i<=n){
id=i;
}
}
ans=check(st+1);
cout<<ans;
cerr<<st+1<<endl;
}
CSP模拟40联测2#
全是诈骗!!
地理课#
前置知识: 线段树分治
一种离线处理方法
可以处理“具体哪个修改对询问有影响”、可以贡献不独立、可以支持插入删除。
对这道题来说,对修改开线段树,线段树上每个节点开一个
然后从根节点递归,先左子树再右子树,对途中经过的结点上的线段计算答案,这里用不压缩路径的并查集维护。对于加入,只需要将个数小的合并到个数多的(启发式合并),只需要将祖先的父亲和大小更改,所以开一个栈维护这个操作,对于删除就是将祖先更改过来。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
const int mod=1e9+7;
struct asd{
int op,x,y;
}a[N],b[N];
struct tree{
int l,r;
}tr[N*4];
struct qwe{
int x,y,sizx,sizy;
}st[N];
int top=0;
vector<int> s[N*4];
map<int,int> mp[N],rk[N];
int cnt=0;
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;
}
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
if(l==r) return;
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
}
void change(int p,int l,int r,int v){
if(tr[p].l>=l && tr[p].r<=r){
s[p].push_back(v);
return;
}
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);
}
int fa[N];
int sum[N];
int get_fa(int x){
if(fa[x]==x) return x;
else return get_fa(fa[x]);
}
int ans=1;
int anss[N];
void add(int p){
for(int i=0;i<s[p].size();i++){
int id=s[p][i];
int x=b[id].x,y=b[id].y;
int fx=get_fa(x),fy=get_fa(y);
if(fx==fy) continue;
if(sum[fx]>sum[fy]) swap(fx,fy);
st[++top]={fx,fy,sum[fx],sum[fy]};
fa[fx]=fy;
ans=ans*(sum[fx]+sum[fy])%mod*mgml(sum[fx]*sum[fy]%mod,mod-2)%mod;
ans%=mod;
sum[fy]+=sum[fx];
}
}
void dele(int now,int p){
while(top>now){
int x=st[top].x,y=st[top].y;
int sizx=st[top].sizx,sizy=st[top].sizy;
ans=ans*sizx%mod*sizy%mod*mgml((sizx+sizy)%mod,mod-2)%mod;
ans%=mod;
fa[x]=x,fa[y]=y;
sum[x]=sizx,sum[y]=sizy;
top--;
}
}
void dfs(int p){
int now=top;
add(p);
if(tr[p].l==tr[p].r){
anss[tr[p].l]=ans;
}
else{
dfs(p*2),dfs(p*2+1);
}
dele(now,p);
}
signed main(){
int n,m;
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
fa[i]=i;
sum[i]=1;
}
build(1,1,m);
for(int i=1;i<=m;i++){
scanf("%lld%lld%lld",&a[i].op,&a[i].x,&a[i].y);
if(rk[a[i].x][a[i].y]==0){
rk[a[i].x][a[i].y]=rk[a[i].x][a[i].y]=++cnt;
b[cnt].x=a[i].x,b[cnt].y=a[i].y;
}
}
for(int i=1;i<=m;i++){
if(a[i].op==1){
mp[a[i].x][a[i].y]=mp[a[i].y][a[i].x]=i;
}
else{
int st=mp[a[i].x][a[i].y];
mp[a[i].x][a[i].y]=mp[a[i].y][a[i].x]=0;
change(1,st,i-1,rk[a[i].x][a[i].y]);
}
}
for(int i=1;i<=m;i++){
if(mp[a[i].x][a[i].y]){
int st=mp[a[i].x][a[i].y];
mp[a[i].x][a[i].y]=mp[a[i].y][a[i].x]=0;
change(1,st,m,rk[a[i].x][a[i].y]);
}
}
dfs(1);
for(int i=1;i<=m;i++){
cout<<anss[i]<<endl;
}
}
CSP模拟41联测3#
超级加倍#
建两棵树
考虑怎么建,以第一棵为例,从
然后就变成求点对
得到有第一棵树的
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2*1e6+5;
int a[N];
int n;
int head_1[N*2],ver_1[N*2],nex_1[N*2],tot_1=0;
void add_1(int x,int y){
ver_1[++tot_1]=y,nex_1[tot_1]=head_1[x],head_1[x]=tot_1;
}
int head_2[N*2],ver_2[N*2],nex_2[N*2],tot_2=0;
void add_2(int x,int y){
ver_2[++tot_2]=y,nex_2[tot_2]=head_2[x],head_2[x]=tot_2;
}
int head_3[N*2],ver_3[N*2],nex_3[N*2],tot_3=0;
void add_3(int x,int y){
ver_3[++tot_3]=y,nex_3[tot_3]=head_3[x],head_3[x]=tot_3;
}
int fa[N];
int get_fa(int x){
if(fa[x]==x) return x;
else return fa[x]=get_fa(fa[x]);
}
int id[N],cnt=0,rk[N],size[N];
void dfs_1(int x,int f){
id[x]=++cnt;
rk[cnt]=x;
size[x]=1;
for(int i=head_2[x];i;i=nex_2[i]){
int y=ver_2[i];
if(y==f) continue;
dfs_1(y,x);
size[x]+=size[y];
}
}
int c[N];
int lowbit(int x){
return x&(-x);
}
void add(int x,int v){
for(;x<=n;x+=lowbit(x)) c[x]+=v;
return;
}
int ask(int x){
if(x==0) return 0;
int ans=0;
for(;x;x-=lowbit(x)) ans+=c[x];
return ans;
}
int ans=0;
void dfs_2(int x,int f){
ans+=ask(id[x]+size[x]-1)-ask(id[x]-1);
add(id[x],1);
for(int i=head_3[x];i;i=nex_3[i]){
int y=ver_3[i];
if(y==f) continue;
dfs_2(y,x);
}
add(id[x],-1);
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
fa[i]=i;
int x;
scanf("%lld",&x);
if(x==0) continue;
add_1(x,i);add_1(i,x);
}
for(int x=1;x<=n;x++){
for(int i=head_1[x];i;i=nex_1[i]){
int y=ver_1[i];
if(y<x){
int fy=get_fa(y);
add_2(x,fy),add_2(fy,x);
fa[fy]=x;
}
}
}
dfs_1(n,0);
for(int i=1;i<=n;i++) fa[i]=i;
for(int x=n;x>=1;x--){
for(int i=head_1[x];i;i=nex_1[i]){
int y=ver_1[i];
if(y>x){
int fy=get_fa(y);
add_3(x,fy),add_3(fy,x);
fa[fy]=x;
}
}
}
dfs_2(1,0);
cout<<ans<<endl;
}
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5*1e5+5;
int n,ls,rs;
struct asd{
int x,v;
}a[N];
struct qwe{
int t,x,y;
}c[N],b[N];
int t1,t2;
int tp=0,tp1=0;
int check(int d){
int ans=0;
int p=0;
a[0].x=-(1ll<<50);
int sum=0;
int pos=0;
while(pos<=n){
while(a[pos].v!=-1){
pos++;
if(a[pos].v==1) sum++;
}
while(a[pos].x-a[p].x>d){
if(a[p].v==1) sum--;
p++;
}
ans+=sum;
pos++;
if(a[pos].v==1) sum++;
}
return ans;
}
set<int> s;
void work(){
s.clear();
int p1=0,p2=0;
int sum=0;
int pos=0;
while(pos<=n){
while(a[pos].v!=-1){
pos++;
if(a[pos].v==1) sum++;
}
while(a[p2+1].x+t1<=a[pos].x){
p2++;
if(a[p2].v==1) s.insert(p2);
}
while(a[p1+1].x+t2<=a[pos].x){
if(a[p1].v==1 && sum) sum--,s.erase(s.find(p1));
p1++;
}
set<int>::iterator it;
int cnt=0;
if(sum){
for(it=s.begin();it!=s.end();it++){
b[++tp].t=a[pos].x-a[*it].x;
int id=sum-cnt;
cnt++;
b[tp].x=pos-id,b[tp].y=pos-(id-1);
}
}
pos++;
if(a[pos].v==1) sum++;
}
}
void work1(int d){
s.clear();
int p1=0,p2=0;
int sum=0;
int pos=0;
while(pos<=n){
while(a[pos].v!=-1){
pos++;
if(a[pos].v==1) sum++;
}
while(a[p2+1].x+d<=a[pos].x){
p2++;
if(a[p2].v==1) s.insert(p2);
}
while(a[p1+1].x+d<=a[pos].x){
if(a[p1].v==1 && sum) sum--,s.erase(s.find(p1));
p1++;
}
set<int>::iterator it;
int cnt=0;
if(sum){
for(it=s.begin();it!=s.end();it++){
b[++tp].t=a[pos].x-a[*it].x;
int id=sum-cnt;
cnt++;
b[tp].x=pos-id,b[tp].y=pos-(id-1);
}
}
pos++;
if(a[pos].v==1) sum++;
}
}
bool amp(asd a,asd b){
return a.x<b.x;
}
bool bmp(qwe a,qwe b){
if(a.t==b.t){
if(a.x==b.x) return a.y<b.y;
else return a.x<b.x;
}
else return a.t<b.t;
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].v);
sort(a+1,a+n+1,amp);
scanf("%lld%lld",&ls,&rs);
// for(int i=0;i<=40;i++){
// cout<<i<<": "<<check(i)<<endl;
// }
int l=0,r=N;
while(l<r){
int mid=(l+r)/2;
if(check(mid)>=ls) r=mid;
else l=mid+1;
}
t1=l;
l=0;r=N;
while(l<r){
int mid=(l+r)/2;
if(check(mid)>=rs) r=mid;
else l=mid+1;
}
t2=l;
if(check(t2)>rs) t2--;
// cout<<t1<<" "<<t2<<endl;
work();
int sum1=ls-check(t1-1)-1;
if(sum1>0){
tp1=0;
work1(t1-1);
sort(c+1,c+tp1+1,bmp);
for(int i=tp1;i>=tp1-sum1+1;i--){
b[++tp].t=c[i].t,b[tp].x=c[i].x,b[tp].y=c[i].y;
}
}
int sum2=rs-check(t2);
if(sum2>0){
work1(t2+1);
tp1=0;
sort(c+1,c+tp1+1,bmp);
for(int i=1;i<=sum2;i++){
b[++tp].t=c[i].t,b[tp].x=c[i].x,b[tp].y=c[i].y;
}
}
sort(b+1,b+tp+1,bmp);
for(int i=1;i<=tp;i++){
cout<<b[i].x<<" "<<b[i].y<<endl;
}
}
#include<bits/stdc++.h>
#define N 300010
using namespace std;
struct points{
long long posi,v;
long long id;
}pi[N];
bool cmp(points a,points b){
return a.posi<b.posi;
}
long long s[N],n;
long long work(long long mid){
long long sum=0,an=0;
long long l=1;
for(long long i=1;i<=n;i++){
if(pi[i].v==1) sum++;
else{
while(pi[i].posi-pi[l].posi>mid){
if(pi[l].v==1) sum--;
l++;
}
an+=sum;
}
}
return an;
}
struct three{
long long x,y,t;
}pa[N];
bool cmps(three a,three b){
if(a.t!=b.t) return a.t<b.t;
if(a.x!=b.x) return a.x<b.x;
if(a.y!=b.y) return a.y<b.y;
}
pair<long long,long long>ps[N],ans[N];
long long tot=0,all=0;
int main(){
// freopen("collision4.in","r",stdin);
// freopen("out.txt","w",stdout);
long long l,r;
scanf("%lld",&n);
s[0]=0;
for(long long i=1;i<=n;i++){
scanf("%lld%lld",&pi[i].posi,&pi[i].v);
pi[i].id=i;
s[i]=s[i-1];
if(pi[i].v==-1) s[i]++;
}
sort(pi+1,pi+n+1,cmp);
scanf("%lld%lld",&l,&r);
// for(int i=0;i<=40;i++){
// cout<<i<<" "<<work(i)<<endl;
// }
// return 0;
long long ls=0,rs=2e9+1,lans,anss;
while(ls<=rs){
long long mid=(ls+rs)>>1;
anss=work(mid);
if(anss>=l) lans=mid,rs=mid-1;
else ls=mid+1;
}
anss=work(lans);
long long p=n;
for(long long i=n;i>=1;i--){
while(pi[p].posi-pi[i].posi>lans) p--;
if(pi[p].v==-1&&pi[i].v==1&&pi[p].posi-pi[i].posi==lans) ps[++tot]={pi[i+s[p-1]-s[i-1]].id,pi[i+s[p-1]-s[i-1]+1].id};
}
sort(ps+1,ps+tot+1);
anss=anss-l+1;
for(long long i=tot-anss+1;i<=tot;i++) ans[++all]=ps[i];
ls=0,rs=2e9+1;
long long rans;
while(ls<=rs){
long long mid=(ls+rs)>>1;
anss=work(mid);
if(anss>=r) rans=mid,rs=mid-1;
else ls=mid+1;
}
work(rans);
if(rans==lans) all=r-l+1;
else{
p=n;
tot=0;
for(long long i=n;i>=1;i--){
while(pi[p].posi-pi[i].posi>rans) p--;
long long pp=p;
while(pi[pp].posi-pi[i].posi>lans){
if(pi[pp].v==-1&&pi[i].v==1) pa[++tot]={pi[i+s[pp-1]-s[i-1]].id,pi[i+s[pp-1]-s[i-1]+1].id,pi[pp].posi-pi[i].posi};
pp--;
}
}
sort(pa+1,pa+tot+1,cmps);
for(long long i=1;all<r-l+1;i++){
all++;
ans[all].first=pa[i].x;
ans[all].second=pa[i].y;
}
}
for(long long i=1;i<=all;i++) printf("%lld %lld\n",ans[i].first,ans[i].second);
return 0;
}
*/
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5*1e5+5;
int n,ls,rs;
struct asd{
int x,v;
}a[N];
struct qwe{
int t,x,y;
}b[N],ans[N],c[N];
int tp=0;
int t1,t2;
int check(int d){
int ans=0;
int p=0;
a[0].x=-(1ll<<50);
int sum=0;
int pos=0;
while(pos<=n){
while(a[pos].v!=-1 && pos<=n){
pos++;
if(a[pos].v==1) sum++;
}
if(pos>n) break;
while(a[pos].x-a[p].x>d){
if(a[p].v==1) sum--;
p++;
}
ans+=sum;
pos++;
if(a[pos].v==1) sum++;
}
return ans;
}
bool bmp(qwe a,qwe b){
if(a.t==b.t){
if(a.x==b.x) return a.y<b.y;
else return a.x<b.x;
}
else return a.t<b.t;
}
int s[N];
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&a[i].x,&a[i].v);
s[i]=s[i-1]+(a[i].v==-1);
}
scanf("%lld%lld",&ls,&rs);
// for(int i=0;i<=30;i++){
// cout<<i<<": "<<check(i)<<endl;
// }
// return 0;
int l=0,r=2e9+10;
while(l<r){
int mid=(l+r)/2;
if(check(mid)>=ls) r=mid;
else l=mid+1;
}
t1=l;
int anss=check(t1);
int p=n;
for(int i=n;i>=1;i--){
while(a[p].x-a[i].x>t1) p--;
if(a[p].v==-1 && a[i].v==1 && a[p].x-a[i].x==t1){
b[++tp]={t1,i+s[p-1]-s[i-1],i+s[p-1]-s[i-1]+1};
}
}
sort(b+1,b+tp+1,bmp);
anss=anss-ls+1;
int all=0;
for(int i=tp-anss+1;i<=tp;i++){
ans[++all]=b[i];
}
l=0;r=2e9+10;
while(l<r){
int mid=(l+r)/2;
if(check(mid)>=rs) r=mid;
else l=mid+1;
}
t2=l;
// cout<<t1<<" "<<t2<<endl;
if(t1==t2) all=rs-ls+1;
else{
p=n;
tp=0;
for(int i=n;i>=1;i--){
while(a[p].x-a[i].x>t2) p--;
int pp=p;
while(a[pp].x-a[i].x>t1){
if(a[pp].v==-1 && a[i].v==1){
c[++tp]={a[pp].x-a[i].x,i+s[pp-1]-s[i-1],i+s[pp-1]-s[i-1]+1};
}
pp--;
}
}
sort(c+1,c+tp+1,bmp);
for(int i=1;all<rs-ls+1;i++){
ans[++all]=c[i];
}
}
for(int i=1;i<=all;i++){
cout<<ans[i].x<<" "<<ans[i].y<<endl;
}
}
/*
4
1 1
2 1
3 -1
4 -1
2 4
*/
作者:bloss
出处:https://www.cnblogs.com/jinjiaqioi/p/17703576.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效