A:甚至连题面都不用仔细看,看一下样例就知道是要把大的和小的配对了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 200010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,id[N],ans[N]; struct data { int x,y,i; bool operator <(const data&a) const { return y<a.y; } }a[N]; bool cmp(const data&a,const data&b) { return a.x>b.x; } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(); for (int i=1;i<=n;i++) a[i].x=read(); for (int i=1;i<=n;i++) a[i].y=read(),a[i].i=i; sort(a+1,a+n+1); for (int i=1;i<=n;i++) id[i]=a[i].i;//��i����id[i] sort(a+1,a+n+1,cmp); for (int i=1;i<=n;i++) ans[id[i]]=a[i].x; for (int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; //NOTICE LONG LONG!!!!! }
B:vp时拿命想都不会,结果一看sol发现idea还很大一部分是我自己造过的题,简直自闭。显然度数之和应该是偶数,先给不要求度数的随便分配一下满足要求。然后找一棵生成树,自底向上只选树边以满足度数要求即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 300010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,a[N],p[N],ans[N],u,t; bool flag[N]; struct data{int to,nxt; }edge[N<<1]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void dfs(int k) { flag[k]=1; for (int i=p[k];i;i=edge[i].nxt) if (!flag[edge[i].to]) { dfs(edge[i].to); if (a[edge[i].to]) ans[++u]=(i-1)/2+1,a[k]^=1; } } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(),m=read();int cnt=0,cnt2=0; for (int i=1;i<=n;i++) a[i]=read(),cnt+=(a[i]==-1),cnt2+=(a[i]==1); if (cnt==0&&(cnt2&1)) {cout<<-1;return 0;} for (int i=1;i<=n;i++) if (a[i]==-1) if (cnt2&1) cnt2=0,a[i]=1;else a[i]=0; for (int i=1;i<=m;i++) { int x=read(),y=read(); addedge(x,y),addedge(y,x); } dfs(1); cout<<u<<endl; for (int i=1;i<=u;i++) printf("%d ",ans[i]); return 0; //NOTICE LONG LONG!!!!! }
C:我省去年初中组直接把这个题搬过来压轴,很久以前口胡过然而并没有写,于是vp时就去搬了份代码交了()。
显然可以先把每个数的平方因子去掉。然后即相当于要求相邻两数存在不同的质因子。也就相当于要求相邻两数不同。于是把所有数排个序,从小到大考虑每种数,设f[i][j][k]为前i个数当前有j对相同数相邻且其中有k对和当前数相同,转移显然。
D:显然满足条件的数一定是区间内出现次数前k大的。考虑回滚莫队,维护一下出现次数区间前5大的数即可。稍微卡卡常就行了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 300010 #define ll long long int n,m,a[N],b[N],cnt[N],mx[6],ans[N],tmp_mx[6]; struct data { int x,y,k,i,u; bool operator <(const data&a) const { return k<a.k||k==a.k&&y<a.y; } }q[N]; void ins(int qwq) { if (cnt[qwq]<cnt[mx[5]]) return; int p=0; for (int k=1;k<=5;k++) if (mx[k]==qwq) {p=k;break;} if (!p) mx[5]=qwq,p=5; while (p>1&&cnt[mx[p]]>cnt[mx[p-1]]) swap(mx[p],mx[p-1]),p--; } int main() { #ifndef ONLINE_JUDGE freopen("b.in","r",stdin); freopen("b.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i]=read(); int block=sqrt(n); for (int i=1;i<=m;i++) q[i].x=read(),q[i].y=read(),q[i].u=read(),q[i].k=q[i].x/block,q[i].i=i; sort(q+1,q+m+1); for (int i=1;i<=m;i++) { for (int k=1;k<=5;k++) mx[k]=0; int t=i;while (t<m&&q[t+1].k==q[i].k) t++; while (i<=t&&q[i].y<(q[i].k+1)*block) { for (int j=q[i].x;j<=q[i].y;j++) { cnt[a[j]]++; ins(a[j]); } ans[q[i].i]=N; for (int k=1;k<=5;k++) if (1ll*cnt[mx[k]]*q[i].u>q[i].y-q[i].x+1) ans[q[i].i]=min(ans[q[i].i],mx[k]); if (ans[q[i].i]==N) ans[q[i].i]=-1; for (int j=q[i].x;j<=q[i].y;j++) cnt[a[j]]--; i++; for (int k=1;k<=5;k++) mx[k]=0; } int r=(q[i].k+1)*block-1; for (int j=i;j<=t;j++) { while (r<q[j].y) { cnt[a[++r]]++; ins(a[r]); } for (int k=1;k<=5;k++) tmp_mx[k]=mx[k]; for (int k=(q[i].k+1)*block-1;k>=q[j].x;k--) { cnt[a[k]]++; ins(a[k]); } ans[q[j].i]=N; for (int k=1;k<=5;k++) if (1ll*cnt[mx[k]]*q[j].u>q[j].y-q[j].x+1) ans[q[j].i]=min(ans[q[j].i],mx[k]); if (ans[q[j].i]==N) ans[q[j].i]=-1; for (int k=(q[i].k+1)*block-1;k>=q[j].x;k--) cnt[a[k]]--; for (int k=1;k<=5;k++) mx[k]=tmp_mx[k]; } r=(q[i].k+1)*block-1; for (int j=i;j<=t;j++) while (r<q[j].y) cnt[a[++r]]=0; i=t; } for (int i=1;i<=m;i++) printf("%d ",ans[i]); return 0; }
事实上直接拿棵主席树在上面暴力查询复杂度大约就是O(knlogn)。具体并不会证。感觉很对就行了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 300010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,root[N],a[N],cnt; struct data{int l,r,x; }tree[N<<5]; void ins(int &k,int l,int r,int x) { tree[++cnt]=tree[k];k=cnt;tree[k].x++; if (l==r) return; int mid=l+r>>1; if (x<=mid) ins(tree[k].l,l,mid,x); else ins(tree[k].r,mid+1,r,x); } int query(int x,int y,int l,int r,int u) { if (tree[y].x-tree[x].x<=u) return -1; if (l==r) return l; int mid=l+r>>1; int v=query(tree[x].l,tree[y].l,l,mid,u); if (v==-1) return query(tree[x].r,tree[y].r,mid+1,r,u); else return v; } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=n;i++) { root[i]=root[i-1]; ins(root[i],1,n,a[i]); } for (int i=1;i<=m;i++) { int l=read(),r=read(),x=read(); printf("%d ",query(root[l-1],root[r],1,n,(r-l+1)/x)); } return 0; //NOTICE LONG LONG!!!!! }
E:因为用来异或的dist随祖先深度减小连续递增,考虑一个套路的对位运算的分块,即固定高位的前一半数字,不妨设令其去掉后9位的部分相同。那么即对于每个点,考虑其向上29个点作为一块。对于每一块,考虑以前一半数字建trie,叶子处存储ai^x的最大值,其中x是其与该块下端点的深度差,因为深度差的后9位对于该块每个点来说在所有需要用到该块的查询中都是一样的。这样预处理的复杂度是7*29*n。考虑查询,从查询点往上暴跳考虑每个块,如果块不完整显然暴力即可,否则先对前一半数字trie上按位贪心,贪完之后即可固定答案中点i的ai前一半数字,并且可以发现答案已经被预处理出来了。查询复杂度q*(29+n*7/29)。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 50010 #define M 150010 #define BLOCK 512 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,a[N],p[N],fa[N],fa512[N],deep[N],root[N],f[N][N/BLOCK+10],trie[N*256][2],t,cnt; struct data{int to,nxt; }edge[N<<1]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void dfs(int k) { for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=fa[k]) { fa[edge[i].to]=k; deep[edge[i].to]=deep[k]+1; dfs(edge[i].to); } } void ins(int &k,int x) { if (!k) k=++cnt; for (int i=k,j=6;j>=0;j--) { if (!trie[i][(x&(1<<j))>0]) trie[i][(x&(1<<j))>0]=++cnt; i=trie[i][(x&(1<<j))>0]; } } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<n;i++) { int x=read(),y=read(); addedge(x,y),addedge(y,x); } dfs(1); for (int i=1;i<=n;i++) if (deep[i]>=BLOCK) { fa512[i]=i; for (int j=0;j<BLOCK;j++) { int x=fa512[i]; ins(root[i],a[x]>>9); f[i][a[x]>>9]=max(f[i][a[x]>>9],a[x]^j); fa512[i]=fa[fa512[i]]; } } for (int i=1;i<=m;i++) { int y=read(),x=read(),u=x,v=0,ans=0; while (deep[u]-deep[y]>=BLOCK) { int w=0; for (int k=root[u],j=6;j>=0;j--) if (v&(1<<j)) { if (trie[k][0]) k=trie[k][0],w=w<<1; else k=trie[k][1],w=w<<1|1; } else { if (trie[k][1]) k=trie[k][1],w=w<<1|1; else k=trie[k][0],w=w<<1; } ans=max(ans,f[u][w]^(v<<9));u=fa512[u];v++; } while (u!=y) ans=max(ans,a[u]^deep[x]-deep[u]),u=fa[u]; ans=max(ans,a[y]^deep[x]-deep[y]); printf("%d ",ans); } return 0; //NOTICE LONG LONG!!!!! }