今日份的博客!!!
专门鸽掉了 Binomial Sum 来更博,良心博主啊!
啊啊啊,最近越来越不想写代码了怎么办。
003 CF1695E Ambiguous Dominoes
遇到图论的题就不会做,怎么说!
下面通过构造来证明,除非问题无解,否则我们一定存在一种方法使得所有多米诺骨牌可以放在 \(2\times n\) 的矩形内。
我们对于一个多米诺骨牌,连接 \((x_i,y_i)\),那么一个连通块可以一起考虑。
对于一个连通块,我们搜出一个欧拉序(长度为二倍边数加一),我们去掉结尾,然后直接盘成一圈放在前面,可以发现从任意位置开始依次放置骨牌都是合法方案,那么第一个方案从 \(1\) 开始放,第二个方案从 \(2\) 开始放就好了。
复杂度 \(O(n+m)\)。
#include<stdio.h>
#include<vector>
using namespace std;
const int maxn=300005;
int n,dfns;
int xx[maxn],yy[maxn],vise[maxn],dfn[maxn<<1],visp[maxn<<1],ans[2][maxn<<1],res[maxn<<1];
vector<int>v[maxn<<1];
void dfs(int x){
dfn[++dfns]=x;
if(visp[x])
return ;
visp[x]=1;
while(!v[x].empty()){
int k=v[x].back(),y=xx[k]+yy[k]-x;
v[x].pop_back();
if(vise[k])
continue;
vise[k]=1,dfs(y),dfn[++dfns]=x;
}
}
int main(){
scanf("%d",&n);
for(int i=1,x,y;i<=n;i++)
scanf("%d%d",&x,&y),v[x].push_back(i),v[y].push_back(i),xx[i]=x,yy[i]=y;
int L=1,R=n+1;
for(int i=1;i<=n+n;i++)
if(v[i].size()){
dfs(i),dfns--;
if(dfns==2){
puts("-1");
return 0;
}
int v=0;
for(int j=1;j<=dfns/2;j++){
res[L]=dfn[j];
ans[0][L]=v==0? (j==dfns/2? 'U':'L'):'R';
ans[1][L]=(j==1)? 'U':(v==1? (j==dfns/2? 'U':'L'):'R');
L++,v^=1;
}
R+=dfns/2;
for(int j=1;j<=dfns/2;j++){
res[R-j]=dfn[dfns/2+j];
ans[0][R-j]=v==1? (j==1? 'D':'L'):'R';
ans[1][R-j]=(j==dfns/2)? 'D':(v==0? (j==1? 'D':'L'):'R');
v^=1;
}
dfns=0;
}
printf("2 %d\n",n);
for(int i=1;i<=n+n;i++)
printf("%d%c",res[i],i%n==0? '\n':' ');
for(int c=0;c<=1;c++)
for(int i=1;i<=n+n;i++){
putchar(ans[c][i]);
if(i%n==0)
putchar('\n');
}
return 0;
}
004 ARC142F Paired Wizards
感觉并不难想,但是很难!
首先要将造成的伤害用一个比较好的式子刻画出来,我们令 \(x_{1,2,\cdots,u}\) 表示第一个人的 2 操作序列,\(y_{1,2,\cdots,v}\) 类似,那么伤害就是:
\[\sum_{i=1}^u(x_i-i)+\sum_{i=1}^v(y_i-i)
\]
也就是说,造成的伤害只与选择的 2 操作下标和,第一个人 2 操作数量,第二个人操作数量有关。
把给定的操作分为四类:
- 两个人的操作都固定;
- 一个人固定,一个人不固定;(分别称为 A,B)
1122
形(称为 C)1221
形(称为 D)
首先预处理出 \(f_i\) 表示第一个人选定了 \(i\) 个非 A 的 2 操作后,使用 A 能带来多少收益,\(g_i\) 同理。
选择的一定是一个后缀,所以我们可以对于一个 \(i\) \(O(n)\) 计算 \(f,g\)。
发现 C 选择的一定是一个后缀,发现 D 造成的下标和贡献是固定的,所以我们可以单纯地枚举使用了多少个 C,以及使用了多少个 D 给第一个人,利用 \(f,g\) 可以 \(O(1)\) 计算答案。
复杂度 \(O(n^2)\)。
#include<stdio.h>
const int maxn=8005;
int n,x,y,sx,sy,tot,sum,ans;
int typ[maxn],f[maxn],g[maxn];
inline int max(int a,int b){
return a>b? a:b;
}
int main(){
scanf("%d",&n);
for(int i=1,a,b,c,d;i<=n;i++){
scanf("%d%d%d%d",&a,&b,&c,&d);
if(a==c||b==d){
if(a==c){
if(a==2)
x++,sx+=i;
if(b!=d)
typ[i]=2;
}
if(b==d){
if(b==2)
y++,sy+=i;
if(a!=c)
typ[i]=1;
}
}
else{
if(a==b)
typ[i]=3;
else tot++,sum+=i;
}
}
for(int i=0;i<=n;i++){
f[i]=-i*(i+1)/2;
for(int j=n,t=i,s=-i*(i+1)/2;j>=1;j--)
if(typ[j]==1)
t++,s+=j-t,f[i]=max(f[i],s);
}
for(int i=0;i<=n;i++){
g[i]=-i*(i+1)/2;
for(int j=n,t=i,s=-i*(i+1)/2;j>=1;j--)
if(typ[j]==2)
t++,s+=j-t,g[i]=max(g[i],s);
}
ans=-1e9;
for(int i=0;i<=tot;i++){
int t=0,s=0;
ans=max(ans,f[x+i]+g[y+(tot-i)]);
for(int j=n;j>=1;j--)
if(typ[j]==3)
t++,s+=j+j,ans=max(ans,f[x+t+i]+g[y+t+(tot-i)]+s);
}
printf("%d\n",ans+sx+sy+sum);
return 0;
}