传送门

\(A\)

根据裴蜀定理显然要\(k|\gcd(a_1,...,a_n)\),顺便注意不能造出大于\(\max(a_1,...,a_n)\)的数

int n,g,k,x,mx;
int main(){
scanf("%d%d",&n,&k);
fp(i,1,n)scanf("%d",&x),g=__gcd(g,x),cmax(mx,x);
puts(k%g==0&&k<=mx?"POSSIBLE":"IMPOSSIBLE");
return 0;
}

\(B\)

对每个人开一个指针,表示他是参加了哪个运动,然后每次把参加人数最多的运动强制不选,同时更新每个人的指针。一直做到指针越界为止,取最优值即可

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=305;
int mp[N][N],cnt[N],id[N],bg[N],vis[N],res,mx,n,m;
int main(){
scanf("%d%d",&n,&m);
fp(i,1,n)fp(j,1,m)scanf("%d",&mp[i][j]);
fp(i,1,n)bg[i]=1,++cnt[mp[i][1]];
res=2333;
while(2333){
mx=0;fp(i,1,m)cmax(mx,cnt[i]);
cmin(res,mx);
fp(i,1,m)if(cnt[i]==mx)vis[i]=1;
fp(i,1,n)while(bg[i]<=m&&vis[mp[i][bg[i]]])++bg[i];
fp(i,1,n)if(bg[i]>m)return printf("%d\n",res),0;
fp(i,1,m)cnt[i]=0;
fp(i,1,n)++cnt[mp[i][bg[i]]];
}
return 0;
}

\(C\)

先考虑二维的情况,即总共有\(n=x+y\)个人,每个人有金币\(a_i\)或银币\(b_i\),那么先假设所有人都取银币,加上前\(x\)大的\(a_i-b_i\)就行了。如果总的个数大于\(n\),那么按\(a_i-b_i\)从大到小排序后,取金币的人必然全部在取银币的人的左边,即存在一个中间点\(k\),满足取金币的人在\([1,k]\),取银币的人在\([k+1,n]\)

对于三维,我们假设所有人都选铜币,并令\(a_i-=c_i,b_i-=c_i\),那么此时转化为之前那种二维的情况了,用堆维护就可以了

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
#define gg(u) for(int &i=cur[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll f[N],g[N],sum,res;int a[N],b[N],c[N],id[N],x,y,z,n,sz;
priority_queue<int,vector<int>,greater<int> >q;
inline bool cmp(const int &x,const int &y){return a[x]-b[x]>a[y]-b[y];}
inline void ins(R int x){sum+=x,q.push(x),++sz;}
inline void del(){sum-=q.top(),q.pop(),--sz;}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d%d",&x,&y,&z),n=x+y+z;
fp(i,1,n){
scanf("%d%d%d",&a[i],&b[i],&c[i]);
a[i]-=c[i],b[i]-=c[i],id[i]=i;
}
sort(id+1,id+1+n,cmp);
sum=sz=0;while(!q.empty())q.pop();
fp(i,1,n){
ins(a[id[i]]);
while(sz>x)del();
if(sz==x)f[i]=sum;
}
sum=sz=0;while(!q.empty())q.pop();
fd(i,n,1){
ins(b[id[i]]);
while(sz>y)del();
if(sz==y)g[i]=sum;
}
res=-1e18;
fp(i,x,n-y)cmax(res,f[i]+g[i+1]);
fp(i,1,n)res+=c[i];
printf("%lld\n",res);
return 0;
}

\(D\)

我是个\(zz\)……

首先对于每条边,设它两边的\(size\)里较小的那个为\(s\),它的权值为\(w\),那么它的贡献上界是\(s\times w\),那么答案上界就是\(\sum s\times w\)

然而上界不可能达到的,我们考虑该减去那些

假设重心是一条边,即两边的\(size\)大小都是\({n\over 2}\),那么对于除了重心的这条边,我们都可以令它被经过次数达到上界,那么答案就是上界减去这条边的权值

假设重心是一个点,那么除了重心到某个子节点的一条边,我们也可以让这些边都达到上界,那么答案就是上界减去重心到子节点的边权中最小的就是了

//quming
#include<bits/stdc++.h>
#define R register
#define pb emplace_back
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
typedef pair<ll,int> pi;
const int N=1e5+5;
struct eg{int v,nx,w;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v,R int w){e[++tot]={v,head[u],w},head[u]=tot;}
inline int min(R int x,R int y){return x<y?x:y;}
ll res;int sz[N],rt,rv,op,mmx,n;
void dfs(int u,int fa,ll dis){
sz[u]=1;
R int mx=0;
go(u)if(v!=fa){
dfs(v,u,dis+e[i].w),sz[u]+=sz[v];
res+=1ll*min(sz[v],n-sz[v])*e[i].w<<1;
if((sz[v]<<1)==n)op=1,rv=e[i].w;
cmax(mx,sz[v]);
}
cmax(mx,n-sz[u]);
if(cmin(mmx,mx))rt=u;
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d",&n),mmx=n+1;
for(R int i=1,u,v,w;i<n;++i){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
dfs(1,0,0);
if(op&1)res-=rv;
else{
R int mn=0x3f3f3f3f;
go(rt)cmin(mn,e[i].w);
res-=mn;
}
printf("%lld\n",res);
return 0;
}

\(E\)

越来越觉得自己好蠢了……

我们先从原点开始考虑,设\(c(x,y)\)表示从原点到\(x,y\)的方案数\((x\geq 0,y\geq 0)\),这个显然为\({x+y\choose x}\)

然后开始推倒

\[\begin{aligned}
\sum_{y=0}^Y c(X,y)=c(X+1,Y)
\end{aligned}
\]

就是说走到\((X+1,Y)\)的方案,就等价于我们枚举在第\(X\)行的哪一列往下走再往右

\[\begin{aligned}
\sum_{x=0}^X\sum_{y=0}^Y c(x,y)=c(X+1,Y+1)-1
\end{aligned}
\]

用前面那个柿子带进去就可以了

\[\begin{aligned}
\sum_{x=X_1}^{X_2}\sum_{y=Y_1}^{Y_2} c(x,y)=C(X_2+1,Y_2+1)-c(X_1,Y_2+1)-c(X_2+1,Y_1)+c(X_1,Y_1)
\end{aligned}
\]

相当于是子矩阵求和,那么变成四个前缀和减一减就好了

然后我们发现一个矩阵可以拆成四个单点求和的形式!

然后我们考虑,起点,中间点,终点的范围都是一个矩阵,如果我们枚举中间点,那么就可以把起点和终点的求和给拆成四个单点的形式,这样就可以\(O(16)\)计算一个中间点的贡献了

考虑如果一条路径经过中间点的那个矩阵,那么贡献就是这条路径和矩阵相交的点的个数,也就是说这条路径要乘上这个个数

我们枚举这条路径是从哪里进矩阵的,从哪里出矩阵的,假设分别是从\((x,y)\)进且从\((xx,yy)\)出,那么贡献就是\(xx-x+yy-y+1\)

那么我们只枚举路径进矩阵的位置,对于路径数乘上\((-x-y)\),再枚举路径出矩阵的位置,对于路径数乘上\(xx+yy+1\),这样我们发现每条合法的路径都会被计算恰好贡献次,所以就没问题了

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=1e9+7;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
const int N=2e6+5;
int fac[N],ifac[N];
void init(int n=2e6){
fac[0]=ifac[0]=1;fp(i,1,n)fac[i]=mul(fac[i-1],i);
ifac[n]=ksm(fac[n],P-2);fd(i,n-1,1)ifac[i]=mul(ifac[i+1],i+1);
}
inline int C(R int n,R int m){return m>n?0:1ll*fac[n]*ifac[m]%P*ifac[n-m]%P;}
inline int calc(R int x,R int y,R int xx,R int yy){
R int res=C(x+y,x);
upd(res,C(xx+1+yy+1,xx+1));
upd(res,P-C(x+yy+1,x));
upd(res,P-C(y+xx+1,y));
return res;
}
int x[15],y[15],res;
inline int t1(R int xx,R int yy){
return calc(xx-x[2],yy-y[2],xx-x[1],yy-y[1]);
}
inline int t2(R int xx,R int yy){
return calc(x[5]-xx,y[5]-yy,x[6]-xx,y[6]-yy);
}
int main(){
// freopen("testdata.in","r",stdin);
init();
fp(i,1,6)scanf("%d",&x[i]);
fp(i,1,6)scanf("%d",&y[i]);
fp(i,x[3],x[4]){
upd(res,1ll*(P-y[3]-i)*t1(i,y[3]-1)%P*t2(i,y[3])%P);
upd(res,1ll*(y[4]+1+i)*t1(i,y[4])%P*t2(i,y[4]+1)%P);
}
fp(j,y[3],y[4]){
upd(res,1ll*(P-x[3]-j)*t1(x[3]-1,j)%P*t2(x[3],j)%P);
upd(res,1ll*(x[4]+1+j)*t1(x[4],j)%P*t2(x[4]+1,j)%P);
}
printf("%d\n",res);
return 0;
}

\(F\)

首先根据每个点的子节点的个数,是可以判断该节点需要填奇数还是偶数的,如果这个奇偶性在两棵树上不同那么显然无解了

否则的话,对于偶节点,我们令其为\(0\),对于每个奇节点的子树中一定有\(2k+1\)个奇节点,我们把这些搞成\(k\)组匹配,对于\((u,v)\)的一组匹配,令\(a_u=1,a_v=-1\)就行了这样子树中的总和的绝对值一定是\(1\)

而对于我们连的边,它一定是一个二分图(否则就会有一个点连了两条边且来自同一棵子树),那么直接黑白染色确定方案就行了

//quming
#include<bits/stdc++.h>
#define R register
#define pb emplace_back
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2e5+5;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
vector<int>t1[N],t2[N];
int a1[N],a2[N],st[N],b[N],rt1,rt2;
int n,top;
void dfs1(int u){
for(auto v:t1[u])dfs1(v);
if(a1[u])st[++top]=u;
while(top>=2){
add(st[top],st[top-1]),add(st[top-1],st[top]);
top-=2;
}
}
void dfs2(int u){
for(auto v:t2[u])dfs2(v);
if(a2[u])st[++top]=u;
while(top>=2){
add(st[top],st[top-1]),add(st[top-1],st[top]);
top-=2;
}
}
void dfs(int u,int c){
b[u]=c;
go(u)if(!b[v])dfs(v,-c);
}
int main(){
scanf("%d",&n);
fp(i,1,n)a1[i]=a2[i]=1;
for(R int i=1,fa;i<=n;++i){
scanf("%d",&fa);
if(fa==-1)rt1=i;else t1[fa].pb(i),a1[fa]^=1;
}
for(R int i=1,fa;i<=n;++i){
scanf("%d",&fa);
if(fa==-1)rt2=i;else t2[fa].pb(i),a2[fa]^=1;
}
fp(i,1,n)if(a1[i]!=a2[i])return puts("IMPOSSIBLE"),0;
puts("POSSIBLE");
top=0,dfs1(rt1);
top=0,dfs2(rt2);
fp(i,1,n)if(a1[i]&&!b[i])dfs(i,1);
fp(i,1,n)printf("%d ",b[i]);
return 0;
}

AtCoder Grand Contest 018题解的更多相关文章

  1. AtCoder Grand Contest 017 题解

    A - Biscuits 题目: 给出 \(n\) 个物品,每个物品有一个权值. 问有多少种选取方式使得物品权值之和 \(\bmod\space 2\) 为 \(p\). \(n \leq 50\) ...

  2. AtCoder Grand Contest 018 D - Tree and Hamilton Path

    题目传送门:https://agc018.contest.atcoder.jp/tasks/agc018_d 题目大意: 给定一棵\(N\)个点的带权树,求最长哈密顿路径(不重不漏经过每个点一次,两点 ...

  3. Atcoder Grand Contest 054 题解

    那天晚上由于毕业晚会与同学吃饭喝酒没打 AGC,第二天稍微补了下题,目前补到了 E,显然 AGC 的 F 对于我来说都是不可做题就没补了(bushi A 简单题,不难发现如果我们通过三次及以上的操作将 ...

  4. AtCoder Grand Contest 030题解

    第一次套刷AtCoder 体验良好 传送门 Poisonous Cookies cout<<b+min(c,a+b+); Tree Burning 难度跨度有点大啊 可以证明当第一次转向之 ...

  5. AtCoder Grand Contest 031题解

    题面 传送门 题解 比赛的之后做完\(AB\)就开始发呆了--简直菜的一笔啊-- \(A - Colorful\ Subsequence\) 如果第\(i\)个字母选,那么它前面任意一个别的字母的选择 ...

  6. AtCoder Grand Contest 018 A

    A - Getting Difference Time limit時間制限 : 2sec / Memory limitメモリ制限 : 256MB 配点 : 300 点 問題文 箱に N 個のボールが入 ...

  7. AtCoder Grand Contest 039 题解

    传送门 \(A\) 首先只有一串的情况下,遇到相同的肯定是改后面那一个最优,然后两串的话可能要分奇偶讨论一下 //quming #include<bits/stdc++.h> #defin ...

  8. AtCoder Grand Contest 017题解

    传送门 \(A\) 直接转移就是了 typedef long long ll; const int N=55; ll f[N][2];int a[N],n,p; int main(){ scanf(& ...

  9. AtCoder Grand Contest 015题解

    传送门 \(A\) 找到能达到的最大的和最小的,那么中间任意一个都可以被表示出来 typedef long long ll; int n,a,b;ll res; int main(){ scanf(& ...

随机推荐

  1. Springboot 整合ApachShiro完成登录验证和权限管理

    1.前言 做一个系统最大的问题就是安全问题以及权限的问题,如何正确的选择一个安全框架对自己的系统进行保护,这方面常用的框架有SpringSecurity,但考虑到它的庞大和复杂,大多数公司还是会选择 ...

  2. git add提交时关于 LF will be replaced by CRLF in 问题出现的原因以及解决方式

    最近在新创建的github项目中add新框架代码时,出现了LF will be replaced by CRLF in的问题,以下为问题截图 查阅资料才知道,LF和FRLF是两种不同的换行格式,这个警 ...

  3. MySQL事务和事务隔离级别

    1.概述 事务就是对数据库数据进行更改(包括insert.update.delete等)操作的一个执行单元,通常有一条或多条更改语句组成.在同一个事务中的更改操作要么同时成功,要么同时失败. 事务具有 ...

  4. Flutter裁剪图片

    最近在学习中需要用到裁剪图片,记录一下解决方法 思路: 使用canvas的drawImageRect()方法,对Image进行裁剪,这里的Image需要 'dart:ui' 库中的Image. 1. ...

  5. ANE打包工具使用视频教程 -- 梦宇技术 @极客学院

    来源:http://xtiqin.blog.163.com/blog/static/17017217920133584934827/ ANE打包工具使用视频教程 2013-04-05 08:49:34 ...

  6. error: unknown filesystem; grub rescue

    我的电脑是win10+ubumtu双系统 在一次windows更新之后,系统无法进入win10和linux系统,出现如图错误 解决方案1: 大部分中文博客的解决方案:这里有个更加详细的: https: ...

  7. js 数组的深度拷贝 的四种实现方法

    首先声明本人资质尚浅,本文只用于个人总结.如有错误,欢迎指正.共同提高. --------------------------------------------------------------- ...

  8. 【Linux下Hadoop-eclipse-plus-3.2.0】编译Hadoop连接eclipse的插件遇见的一系列错误,崩溃的操作

    2019-09-02 23:35:22 前言:首先,我想吐槽下自己,居然花费了4到5个夜晚和中午的时间来做这件事情,直到刚才才顺利解决,我也挺佩服自己的! 我在这个过程中参考其他人的博客,非常感谢他们 ...

  9. redhat6.7 yum网络源配置

    RedHat自带的yum源需要当前系统注册了RHN才可以使用,如果没有注册,当使用yum时,会提示需要注册RHN 如果没有注册RHN,则意味着我们不能使用RedHat自带的yum源.这个时候,我们可以 ...

  10. 【转】TI DSP C6657学习之——编译静态库.lib

    熟悉C++开发的的小伙伴都知道,我们一般代码中往往要引入许多第三方编译好的库,有些是静态链接库static library, 有些是动态链接库dll.引入库的目的一是减少代码的编译时间,二是只提供函数 ...