受某些原因而鸽了考试,然鹅题也没有做完,只能先鸽为妙。
woj4785~4789
阅读题,,实在是不想写了。只要注意long long平方会爆long long,只需要与1e9+1取min再做就行。
#include<bits/stdc++.h> using namespace std; #define in read() #define int long long int in{ int cnt=0,f=1;char ch=0; while(!isdigit(ch)){ ch=getchar();if(ch=='-')f=-1; } while(isdigit(ch)){ cnt=cnt*10+ch-48; ch=getchar(); }return cnt*f; } int n,q,minn; int a[700003]; int Gcd; int gcd(int a,int b){ if(!b)return a; return gcd(b,a%b); } signed main(){ n=in;minn=2e18; for(int i=1;i<=n;i++)minn=min(minn,a[i]=in); Gcd=a[1]; for(int i=2;i<=n;i++)Gcd=gcd(Gcd,a[i]); q=in; while(q--){ int x=in;int op=in; if(op==1){ if(Gcd%x)cout<<"No"<<'\n';else cout<<"Yes"<<'\n'; }else{ x=min(x,(int)(1e9+1)); if(x*x<minn)cout<<"Yes"<<'\n';else cout<<"No"<<'\n'; } } return 0; }类似莫队的桶桶题。维护与正解的差值,0才是好的。每次扫一遍。这道题对于赋0有启发意义。
先鸽,好困qw
题面好长哦。
每个点有子树和权值(均非负)。自己在不作为路径极值的情况下,求能到达的点集或和。
不能极值,分大或小两种。
既然非负,那我肯定比子树大。所以不往子树走。
往上都是比我大的,我不能是最小的。那我的目标肯定是非祖孙的点且要比自己小。
画一棵树,去掉自己的子树,所有比我还小的点,,这个dfs序很好做。
去掉子树,,前后各做一次不就好了吗qwq
友情提示,记得开栈。
#include<bits/stdc++.h> using namespace std; #define in read() int in{ int cnt=0,f=1;char ch=0; while(!isdigit(ch)){ ch=getchar(); if(ch=='-')f=-1; } while(isdigit(ch)){ cnt=cnt*10+ch-48; ch=getchar(); }return cnt*f; } int t[3000003],ans[500003],a[500003],first[500003],nxt[1000003],to[1000003],tot; void add(int a,int b){ nxt[++tot]=first[a];first[a]=tot;to[tot]=b; } int gin[500003],gout[500003],id,pre[500003]; vector<int> before[500003],after[500003]; int n,rt; void dfs(int u,int fa){ gin[u]=++id;pre[id]=u;; for(int i=first[u];i;i=nxt[i]){ int v=to[i];if(v==fa)continue; dfs(v,u);a[u]+=a[v]; }gout[u]=id; } int lowbit(int x){ return x&(-x); } void modify(int x,int key){ while(x<=3000000){ t[x]|=key;x+=lowbit(x); } } int query(int x){ int sum=0; while(x){ sum|=t[x];x-=lowbit(x); }return sum; } signed main(){ int size=40<<20;//40M //__asm__ ("movl %0, %%esp\n"::"r"((char*)malloc(size)+size));//调试用这个 __asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));//提交用这个 //main函数代码 n=in;rt=in; for(int i=1,a,b;i<n;i++)a=in,b=in,add(a,b),add(b,a); for(int i=1;i<=n;i++)a[i]=in; dfs(rt,0); for(int i=1;i<=n;i++){ before[gin[i]-1].push_back(i); after[gout[i]+1].push_back(i); } for(int i=1;i<=n;i++){ modify(a[pre[i]],a[pre[i]]); for(int j=0;j<before[i].size();j++){ int x=before[i][j]; ans[x]|=query(a[x]-1); } } memset(t,0,sizeof(t)); for(int i=n;i>=1;i--){ modify(a[pre[i]],a[pre[i]]); for(int j=0;j<after[i].size();j++){ int x=after[i][j]; ans[x]|=query(a[x]-1); } } for(int i=1;i<=n;i++)cout<<ans[i]<<" "; exit(0); return 0; }是我太菜,想过状压,但我完全没有把能否出现表示成状态的想法。先鸽。
这道题有毒。卡我费用流板子,,明天得换个板子。
很高兴能想出来怎么建图。
我的思维很不成熟,面对题目只能臆测算法。
这道题让我毫无头绪,数据范围让我回想起曾经被计数题吊打的悲惨回忆,想歪了很久。
然后惊觉:这根计数有个什么关系,,求最大贡献不应该想想网络流吗。
然后开始想费用流。
先想怎么合法。合法要全是回路。一个回路,,每个点度数都是2,,
于是第一反应先拆点,每个点有2的流量,向四个方向连边,弄出来每个点都弄满成2就有解。
四个方向,本质实际上是黑白染色,,不过我一开始没往那方面想,后面想贡献时才发现要染色。
但是要算贡献。拐弯的话?
网格图,,四个方向,,方向不同才能有贡献,,
方向不同?那再拆点啊。但流量为2?再加一个控流点。
贡献要打,先最大费用。然后考虑构图。显然,控流点向同一个方向得有两条边。先选大的,然后如果方向相同,会选一个0。
如果不同,两个都选大的。发现这样做,刚好多算了贡献的一次和。所以最后减去就行了。
写着写着发现不对,,没有黑白染色的话,贡献会算炸。于是染了色分开考虑。
然后T了。
#include<bits/stdc++.h> using namespace std; #define in read() int in{ int cnt=0,f=1;char ch=0; while(!isdigit(ch)){ ch=getchar();if(ch=='-')f=-1; } while(isdigit(ch)){ cnt=cnt*10+ch-48; ch=getchar(); }return cnt*f; } int n,m; int first[20003],nxt[200003],to[200003],w[200003],cost[200003],tot=1; int x[4]={-1,1,0,0},y[4]={0,0,-1,1}; int mapp[303][303],a[303][303],id[303][303][3],c[303][303]; int cnt,S,T,all; int Maxflow,Maxcost,maxcost[15003],pre[15003],ww[15003],last[15003],vis[15003]; queue<int> q; inline void add(int a,int b,int c,int d){ //cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl; nxt[++tot]=first[a];first[a]=tot;to[tot]=b;w[tot]=c;cost[tot]=d; nxt[++tot]=first[b];first[b]=tot;to[tot]=a;w[tot]=0;cost[tot]=-d; } inline bool bfs(int s,int t){ memset(maxcost,-0x3f,sizeof(maxcost)); memset(ww,0x3f,sizeof(ww));memset(vis,0,sizeof(vis)); q.push(s);vis[s]=1;maxcost[s]=0;pre[t]=-1; while(!q.empty()){ int u=q.front();q.pop();vis[u]=0; for(register int i=first[u];i;i=nxt[i]){ int v=to[i];if(w[i]&&maxcost[v]<maxcost[u]+cost[i]){ maxcost[v]=maxcost[u]+cost[i]; ww[v]=min(ww[u],w[i]);pre[v]=u;last[v]=i; if(!vis[v])q.push(v),vis[v]=1; } } }return pre[t]!=-1; } inline void dinic(int s,int t){ while(bfs(s,t)){ Maxcost+=maxcost[t]*ww[t];Maxflow+=ww[t]; int now=t; while(now!=s){ w[last[now]]-=ww[t];w[last[now]^1]+=ww[t]; now=pre[now]; } } }int sumall; signed main(){ n=in;m=in; for(register int i=1;i<=n;i++)for(register int j=1;j<=m;j++)mapp[i][j]=in; for(register int i=1;i<=n;i++)for(register int j=1;j<=m;j++) a[i][j]=in,c[i][j]=(i+j)%2,sumall+=(mapp[i][j])?0:a[i][j],\ id[i][j][0]=++cnt,id[i][j][1]=++cnt,id[i][j][2]=++cnt; S=0;T=cnt+1; for(register int i=1;i<=n;i++){ for(register int j=1;j<=m;j++){ if(mapp[i][j])continue; if(c[i][j]){ all+=2;add(S,id[i][j][0],2,0); add(id[i][j][0],id[i][j][1],1,a[i][j]);add(id[i][j][0],id[i][j][1],1,0); add(id[i][j][0],id[i][j][2],1,a[i][j]);add(id[i][j][0],id[i][j][2],1,0); }else{ add(id[i][j][0],T,2,0); add(id[i][j][1],id[i][j][0],1,a[i][j]);add(id[i][j][1],id[i][j][0],1,0); add(id[i][j][2],id[i][j][0],1,a[i][j]);add(id[i][j][2],id[i][j][0],1,0); } } } //cout<<"#"<<endl; for(register int i=1;i<=n;i++){ for(register int j=1;j<=m;j++){ if(mapp[i][j])continue; if(!c[i][j])continue; for(register int k=0;k<4;k++){ int nx=i+x[k],ny=j+y[k]; if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&!mapp[nx][ny]){ if(k==0||k==1)add(id[i][j][1],id[nx][ny][1],1,0); else add(id[i][j][2],id[nx][ny][2],1,0); } } } } dinic(S,T); if(Maxflow<all){ cout<<"-1";return 0; } //cout<<sumall<<" "<<Maxcost<<" "<<Maxflow<<endl; cout<<Maxcost-sumall; return 0; }
