AtCoder Grand Contest 035
Preface
Atcoder的题都好劲啊,都是我做不动的计数与构造
就当锻炼自己的思维能力了(基本都是bzt教的)
A - XOR Circle
bzt说这题数据太水了只要判一下所有数异或值是否为\(0\)就能过,但我们要考虑正解(数据太弱我也不知道到底对不对)
首先我们发现放数的时候必然会出现\(a_1\to a_1\operatorname{xor} a_2\to a_2\to a_1\)的情况,即三个数一组的循环
那么我们可以得到一个普遍的结论:只有三种数且每种数字个数相同
然后你直接提交就会WA掉,原因是忽略了\(0\)的情况,因此我们要加上下面两个特判:
- 全为\(0\)时显然合法
- \(3|n\)且只有两种数(一种是\(0\)),\(0\)的个数为\(\frac{n}{3}\),非零的那个数个数为\(\frac{2n}{3}\)。假设非零数为\(x\),显然可以放置成\(x\to 0\to x\to x\to 0\to x\to \cdots x\to 0\to x\)
#include<cstdio>
#include<cctype>
#include<map>
#include<utility>
#define RI register int
#define CI const int&
#define Tp template <typename T>
#define fi first
#define se second
using namespace std;
typedef pair <int,int> pi;
const int N=100005;
int n,x,size; map <int,int> C;
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
char Fin[S],*A,*B;
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
#undef tc
}F;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (F.read(n),i=1;i<=n;++i)
F.read(x),(!C.count(x))&&(++size),++C[x];
if (size>3) return puts("No"),0; pi a,b,c;
a=*C.begin(); C.erase(C.begin());
if (size==1) return puts(a.fi?"No":"Yes"),0;
if (n%3) return puts("No"),0; b=*C.begin(),C.erase(C.begin());
if (size==2) return puts(!a.fi&&(a.se==n/3&&b.se==n/3*2)?"Yes":"No"),0;
c=*C.begin(),C.erase(C.begin());
if ((a.fi^b.fi)!=c.fi) return puts("No"),0;
if (a.se!=b.se||a.se!=c.se) puts("No"); else puts("Yes"); return 0;
}
B - Even Degrees
构造题,首先一眼发现\(m\)为奇数必然无解,考虑偶数的构造
我们考虑先找出一棵生成树,然后将所有非树边随便定向
然后考虑对于生成树上的边,如果我们以及处理完了其子树内的所有边,那么我们可以直接根据此时它的出度来决定它与父亲的边的方向
然后这样除了根节点所有节点出度都为偶数,然后总边数也是偶数,因此根节点出度必为偶数,于是得到了一种构造方案
#include<cstdio>
#include<cctype>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=100005;
struct edge
{
int to,nxt,id;
}e[N<<1]; int head[N],n,cnt,m,x[N],y[N],out[N],ansx[N],ansy[N],anc[N]; bool vis[N],cs[N];
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[15];
public:
FileInputOutput() { Ftop=Fout; Fend=Fout+S; }
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
Tp inline void write(T x,const char& ch)
{
RI ptop=0; while (pt[++ptop]=x%10,x/=10);
while (ptop) pc(pt[ptop--]+48); pc(ch);
}
inline void flush(void)
{
fwrite(Fout,1,Ftop-Fout,stdout);
}
#undef tc
#undef pc
}F;
inline void addedge(CI x,CI y,CI z)
{
e[++cnt]=(edge){y,head[x],z}; head[x]=cnt;
e[++cnt]=(edge){x,head[y],z}; head[y]=cnt;
}
#define to e[i].to
inline void DFS1(CI now=1)
{
vis[now]=1; for (RI i=head[now];i;i=e[i].nxt)
if (!vis[to]) cs[e[i].id]=1,anc[to]=e[i].id,DFS1(to);
}
inline void DFS2(CI now=1,CI fa=0)
{
for (RI i=head[now];i;i=e[i].nxt) if (cs[e[i].id]&&to!=fa) DFS2(to,now);
if (out[now]&1) ansx[anc[now]]=now,ansy[anc[now]]=fa;
else ansx[anc[now]]=fa,ansy[anc[now]]=now,++out[fa];
}
#undef to
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (F.read(n),F.read(m),i=1;i<=m;++i)
F.read(x[i]),F.read(y[i]),addedge(x[i],y[i],i);
if (m&1) return puts("-1"),0;
for (DFS1(),i=1;i<=m;++i) if (!cs[i])
++out[x[i]],ansx[i]=x[i],ansy[i]=y[i];
for (DFS2(),i=1;i<=m;++i) F.write(ansx[i],' '),F.write(ansy[i],'\n');
return F.flush(),0;
}
C - Skolem XOR Tree
又是构造题,先把无解判了,发现若\(n\)是\(2\)的幂次必然无解(小于它的数这一位上不可能为\(1\))
否则我们可以发现现在的\(n\ge 3\),而\(n=3\)的构造方案样例已经告诉我们了,我们考虑在上面扩展
每次我们按序添加两个点\(i,i+1\),其中\(i\)为偶数,那么我们显然可以构造一条\((i,i+1)-(1,i)-(1,n+i+1)-(n+i+1,n+i)\)的链,显然这样链上就满足了条件
因此若\(n\)为奇数就做完了,然后若\(n\)为偶数只可能剩下最后一个点没选,相当于找一条树上路径异或和为\(n\),直接前缀和处理一下即可
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<map>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,cur,pfx[N<<1]; vector <int> v[N<<1]; map <int,int> Hash;
inline void addedge(CI x,CI y)
{
printf("%d %d\n",x,y); v[x].push_back(y); v[y].push_back(x);
}
inline void DFS(CI now=1,CI fa=0)
{
pfx[now]=pfx[fa]^(now<=n?now:now-n);
if (pfx[now]==n) addedge(1,n),addedge(now,n<<1),exit(0);
if (Hash.count(pfx[now]^n^1))
addedge(Hash[pfx[now]^n^1],n),addedge(now,n<<1),exit(0);
Hash[pfx[now]]=now; for (vector <int>::iterator it=v[now].begin();it!=v[now].end();++it)
if (*it!=fa) DFS(*it,now);
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
scanf("%d",&n); for (cur=1;cur<n;cur<<=1);
if (cur==n) return puts("No"),0; puts("Yes");
addedge(1,2); addedge(2,3); addedge(3,n+1); addedge(n+1,n+2); addedge(n+2,n+3);
for (RI i=5;i<=n;i+=2) addedge(1,i-1),addedge(i,i-1),addedge(1,n+i),addedge(n+i,n+i-1);
if (n&1) return 0; return DFS(),0;
}
D - Add and Remove
思路很妙,代码很短的一题
首先看到数据范围一眼DP,但是发现状态根本不好表示
因此考虑倒序处理这个过程,每次相当于从两边向中间吐出一个数,这样我们就可以求出每个数对答案的贡献\(c_i\)然后乘上位置上的值即可
考虑如果有很多数,它们的贡献\(c_i\)已知,那么如果我们将\(i\)与\(i+1\)间的数吐出来,那么这个数对答案的贡献就是\(c_i+c_{i+1}\)
因此我们可以直接搞一个DP,定义\(f_{l,r,cl,cr}\)表示区间\((l,r)\),左端点的贡献是\(cl\),右端点的贡献是\(cr\),考虑转移:
\]
那么最后的答案就是\(f_{1,n,1,1}+a_1+a_n\),然后由于一些奇怪的东西这个的状态数是\(O(2^n\times Poly(n))\)的,因此直接爆搜就好了
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=20;
int n,a[N];
inline long long DFS(CI l,CI r,CI cl,CI cr)
{
if (r-l+1<=2) return 0; long long ret=1e18;
for (RI i=l+1;i<r;++i) ret=min(ret,DFS(l,i,cl,cl+cr)+DFS(i,r,cl+cr,cr)+1LL*(cl+cr)*a[i]);
return ret;
}
signed main()
{
RI i; for (scanf("%d",&n),i=1;i<=n;++i)
scanf("%d",&a[i]); return printf("%lld",DFS(1,n,1,1)+a[1]+a[n]),0;
}
E - Develop
神仙计数题,被神仙bzt出在了模拟赛里
首先考虑将原问题转化,我们可以发现对于一个状态,可以将每一个数看做一个点,那么如果\(x\)在集合内就向\(x-2\)和\(x+k\)(如果存在)连一条有向边,如果最后得出的图无环即有解
那么我们分\(k\)的奇偶性讨论,首先如果\(k\)是偶数我们可以将原问题的奇偶数分别考虑最后乘起来
那么现在问题等价于选一个数\(x\)就不能选\(x-1\)和\(x+\frac{k}{2}\)
发现其实这就等价于不能有连续\(\frac{k}{2}+1\)个\(1\)被选,直接令\(f_{i,j}\)表示第\(i\)位结尾有\(j\)个连续的\(1\)再DP即可
考虑\(k\)为奇数的情况,我们发现一个环必然是\(a\to a-2\to a-4\to \cdots a-2d+k\to a-2(d+1)+k\to \cdots \to a-2(k-1)+2k\to a\)
即先减去一些\(2\)然后加上一个\(k\)再减去一些\(2\)再加上一个\(k\)
那么分析一下就是选出\(k\)个\(-2\)和\(2\)个\(k\),转化一下就变成选出\(k\)个\(2\)和\(2\)个\(-k\)
我们考虑一种神奇的建模,将奇偶两排点建在左右两边,然后将两排数对齐使得左边的奇数+\(k\)=右边的偶数
然后我们发现一条不合法的路径(即出现环)就是这张图上长度大于等于\(k+2\)的路径(多画画图理解下)
因此我们定义DP状态\(f_{i,j,k}\)表示做到第\(i\)行,一直向下走的路径长为\(j\),走成下-左-下的路径长为\(k\),那么所有\(k\le k+1\)的路径都是合法的,直接转移即可
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=155;
int n,k,mod;
inline void inc(int& x,CI y)
{
if ((x+=y)>=mod) x-=mod;
}
namespace Case1 //Even number solver
{
int f[N][N];
inline int calc(CI n,CI k)
{
RI i,j; for (f[0][0]=i=1;i<=n;++i) for (f[i][0]=f[i-1][0],j=1;j<=k;++j)
inc(f[i][0],f[i-1][j]),f[i][j]=f[i-1][j-1];
int ret=0; for (i=0;i<=k;++i) inc(ret,f[n][i]); return ret;
}
inline void solve(void)
{
printf("%d",1LL*calc(n>>1,k>>1)*calc(n-(n>>1),k>>1)%mod);
}
};
namespace Case2 //Odd number solver
{
int f[N][N][N],ans;
inline void solve(void)
{
RI i,j,p; for (f[0][0][0]=i=1;i<=n;++i)
{
int r=i<<1,l=r-k,fl=1<=l&&l<=n,fr=1<=r&&r<=n;
for (j=0;j<=n;++j) for (p=0;p<=k+1;++p)
{
inc(f[i][0][0],f[i-1][j][p]); if (fr) inc(f[i][j+1][0],f[i-1][j][p]);
if (fl&&p+1<k+2) inc(f[i][0][p?p+1:p],f[i-1][j][p]);
if (fl&&fr&&max(j+2,p+1)<k+2) inc(f[i][j+1][max(j+2,p+1)],f[i-1][j][p]);
}
}
for (i=0;i<=n;++i) for (j=0;j<=k+1;++j)
inc(ans,f[n][i][j]); printf("%d",ans);
}
};
int main()
{
scanf("%d%d%d",&n,&k,&mod); if (k&1) Case2::solve();
else Case1::solve(); return 0;
}
F - Two Histograms
妙不可言的一题,首先我们发现一些不同的操作序列\(k,l\)可能会构造出相同的矩阵,那么我们考虑将一些能构造出相同矩阵的序列用一种方法表示出来就不会计重了
考虑我们可以尽量把一种方案中的\(l\)中的一个数从\(l\)移动到\(k\)中,推导一下发现就是要满足\(k_i+1=j\)且\(l_j=i\)的点对\((i,j)\)
因此我们发现这样每个\(i\)只会和一个\(j\)唯一配对,因此我们可以直接计算出大于等于\(i\)对配对的方案数
那么我们枚举点对数目\(i\),容斥计算即可
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=500005,mod=998244353;
int n,m,d,ans,fact[N],inv[N],pwn[N],pwm[N];
inline void inc(int& x,CI y)
{
if ((x+=y)>=mod) x-=mod;
}
inline void dec(int& x,CI y)
{
if ((x-=y)<0) x+=mod;
}
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void init(CI n,CI m)
{
RI i; for (fact[0]=i=1;i<=m;++i) fact[i]=1LL*fact[i-1]*i%mod;
for (inv[m]=quick_pow(fact[m]),i=m-1;~i;--i) inv[i]=1LL*inv[i+1]*(i+1)%mod;
for (pwn[0]=i=1;i<=m;++i) pwn[i]=1LL*pwn[i-1]*(n+1)%mod;
for (pwm[0]=i=1;i<=m;++i) pwm[i]=1LL*pwm[i-1]*(m+1)%mod;
}
inline int C(CI n,CI m)
{
return 1LL*fact[n]*inv[m]%mod*inv[n-m]%mod;
}
inline int A(CI n,CI m)
{
return 1LL*fact[n]*inv[n-m]%mod;
}
int main()
{
scanf("%d%d",&n,&m); if (n>m) swap(n,m);
init(n,m); for (RI i=0;i<=n;++i)
{
int d=1LL*C(n,i)*A(m,i)%mod*pwm[n-i]%mod*pwn[m-i]%mod;
if (i&1) dec(ans,d); else inc(ans,d);
}
return printf("%d",ans),0;
}
Postscript
感觉AGC好考验思维啊,我可能需要多做一点这样的题目QAQ
AtCoder Grand Contest 035的更多相关文章
- 【AtCoder】AtCoder Grand Contest 035 解题报告
点此进入比赛 \(A\):XOR Circle(点此看题面) 大致题意: 给你\(n\)个数,问是否能将它们摆成一个环,使得环上每个位置都是其相邻两个位置上值的异或值. 先不考虑\(0\),我们假设环 ...
- AtCoder Grand Contest 035 简要题解
从这里开始 题目目录 Problem A XOR Circle 你发现,权值的循环节为 $a_0, a_1, a_0\oplus a_1$,然后暴力即可. Code #include <bits ...
- AtCoder Grand Contest 012
AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...
- AtCoder Grand Contest 011
AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...
- AtCoder Grand Contest 031 简要题解
AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...
- AtCoder Grand Contest 010
AtCoder Grand Contest 010 A - Addition 翻译 黑板上写了\(n\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...
- AtCoder Grand Contest 009
AtCoder Grand Contest 009 A - Multiple Array 翻译 见洛谷 题解 从后往前考虑. #include<iostream> #include< ...
- AtCoder Grand Contest 008
AtCoder Grand Contest 008 A - Simple Calculator 翻译 有一个计算器,上面有一个显示按钮和两个其他的按钮.初始时,计算器上显示的数字是\(x\),现在想把 ...
- AtCoder Grand Contest 007
AtCoder Grand Contest 007 A - Shik and Stone 翻译 见洛谷 题解 傻逼玩意 #include<cstdio> int n,m,tot;char ...
随机推荐
- Azure Automation (7) 执行Azure SQL Job
<Windows Azure Platform 系列文章目录> 之前Automation介绍的内容,是在ASM模式下自动化开关机. 本章将介绍如何在Automation中,设置开关机脚本, ...
- 【前端知识体系-JS相关】深入理解JavaScript原型(继承)和原型链
1. Javascript继承 1.1 原型链继承 function Parent() { this.name = 'zhangsan'; this.children = ['A', 'B', 'C' ...
- 微博Feed流
一.微博核心业务图 二.微博的架构设计图 三.简述 先来看看Feed流中的一些概念: Feed:Feed流中的每一条状态或者消息都是Feed,比如微博中的一条微博就是一个Feed. Feed流:持续更 ...
- [新概念英语] Lesson 12 : GOODBYE AND GOOD LUCK
Lesson 12 : GOODBYE AND GOOD LUCK New words and expressions : luck (n) 运气 例句 You're not having much ...
- MySQL for OPS 01:简介 / 安装初始化 / 用户授权管理
写在前面的话 取这个标题的目的很简单,MySQL 在中小型企业中一般都是由运维来维护的,除非数据很重要的公司可能会聘请 DBA. 但是运维一般存在由于所需要了解的东西很多很杂,导致学习过程中很多东西只 ...
- yii2.0的学习之旅(一)
一. 通过composer安装yii2.0项目 *本文是根据您已经安装了composer (1)跳转到项目根目录 cd /xxxx/www (2)下载插件 composer global requir ...
- [.NET] 控制只启动单个指定外部程序
独立观察员 2019 年 6 月 12 日 有的时候我们程序需要启动外部程序来配合实现某些功能,比如启动一个 Cef 相关程序来承载网页.那么如果那个外部程序并没有实现单例启动,我们程序去启动它的时候 ...
- Python - 面向对象 - 第二十天
Python 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. 如果你以前没有接触过 ...
- java socket通信:聊天器(1)
目的:实现多个客户之间的通信 首先,这个聊天器的框架是这样的: 对于服务器端:建立socket,连接到服务器,并且开始监听. import java.io.*; import java.util.Ar ...
- FCC-学习笔记 Sorted Union
FCC-学习笔记 Sorted Union 1>最近在学习和练习FCC的题目.这个真的比较的好,推荐给大家. 2>中文版的地址:https://www.freecodecamp.cn/; ...