# Codeforces Round #639 (Div. 2)

## A. Puzzle Pieces

#### 题解

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
int T,n,m;
int main()
{
while(T--)
{
if(n>m)swap(n,m);
if(n==1)printf("YES\n");
else if(n==2 && m==2)printf("YES\n");
else printf("NO\n");
}
return 0;
}


## B. Card Constructions

#### 题解

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
int T,n;
LL f[50010];
int func(int x)
{
if(x<=0)return 0;
int pos=lower_bound(f+1,f+50000+1,x)-f;
if(f[pos]==x)return 1;
if(f[pos-1]==0)return 0;
return 1+func(x-f[pos-1]);
}
int main()
{
f[1]=2;
for(int i=2;i<=50000;i++)f[i]=f[i-1]+3ll*i-1ll;
while(T--)
{
printf("%d\n",func(n));
}
return 0;
}


# C. Hilbert's Hotel

#### 题解

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int maxn=200010;
int T,n,a;
bool vis[maxn];
int main()
{
while(T--)
{
bool ok=0;
for(int i=0;i<n;i++)vis[i]=0;
for(int i=1;i<=n;i++)
{
if(vis[a]==1 && !ok){
printf("NO\n");
ok=1;
}
vis[a]=1;
}
if(!ok)printf("YES\n");
}
return 0;
}


## D. Monopole Magnets

#### 题解

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int maxn=1010;
int n,m,ans,dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
char pic[maxn][maxn];
bool vis[maxn][maxn],heng[maxn],shu[maxn];
bool legal(int x,int y){return x>=0 && x<n && y>=0 && y<m;}
void dfs(int x,int y,int col)
{
vis[x][y]=1;
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(legal(nx,ny) && pic[nx][ny]=='#' && !vis[nx][ny])dfs(nx,ny,col);
}
}
int main()
{
for(int i=0;i<n;i++)scanf("%s",pic[i]);
bool ass=0;
for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(pic[i][j]=='#')ass=1;
if(!ass)return puts("0"),0;
for(int i=0;i<n;i++)
{
int ok=0;
for(int j=0;j<m;j++)if(pic[i][j]=='#')ok=1;
if(!ok)heng[i]=1;
}
for(int i=0;i<m;i++)
{
int ok=0;
for(int j=0;j<n;j++)if(pic[j][i]=='#')ok=1;
if(!ok)shu[i]=1;
}
for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(heng[i] && shu[j])vis[i][j]=1;//,printf("%d %d\n",i,j);
for(int i=0;i<n;i++)
{
int ok=0,ok2=0;
for(int j=0;j<m;j++)
{
if(vis[i][j])ok2=1;
if(pic[i][j]=='#')
{
ok++;
while(j<m && pic[i][j]=='#')j++;
}
}
if(ok>1 || (!ok2 && !ok))return puts("-1"),0;
}
for(int i=0;i<m;i++)
{
int ok=0,ok2=0;
for(int j=0;j<n;j++)
{
if(vis[j][i])ok2=1;
if(pic[j][i]=='#')
{
ok++;
while(j<n && pic[j][i]=='#')j++;
}
}
if(ok>1 || (!ok2 && !ok))return puts("-1"),0;
}
for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(pic[i][j]=='#' && !vis[i][j])dfs(i,j,++ans);
printf("%d\n",ans);
return 0;
}


## F. Résumé Review

#### 题解

$f(b_1,...,b_n)=\sum^{n}_{i=1} b_i*(a_i-b_i^2)$

$\sum b_i=k$
$0 \leq b_i \leq a_i$$n$ 组。

$\frac{\part f}{\part b_i}$ = $b_i(a_i-b_i^2) - (b_i-1)(a_i-(b_i-1)^2) =a_i-3b_i^2+3b_i+1$ ,显然是一个关于$b_i$ 的二次函数，其中$0 \leq b_i \leq a_i$。很巧的是，这个二次函数的对称轴为$x=\frac{1}{2}$ ，在$x=1,2,3$ 这种离散取值中完全是单调递减的,所以为了让目标函数最大，这些$b_i$ 显然应该更靠左更好，只需要满足$\sum b_i=k$即可，所以我们就可以完全无视这$n$ 个约束条件：$0 \leq b_i \leq a_i$。剩下的就套用正常拉格朗日数乘的规则，使得目标函数的梯度$\nabla = (\frac{\part f}{\part b_1} ,...,\frac{\part f}{\part b_n})$与约束条件函数的梯度$(1,..,1)$平行，当然了这个梯度是离散梯度。

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<LL,LL> PII;
#define X first
#define Y second
{
LL x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10ll+c-'0';c=getchar();}
return x*f;
}

const int maxn=100010;
LL F(LL x,LL y){return x-3ll*y*y+3ll*y-1;}
LL n,k,a[maxn],L=9e18,R=-9e18,ans[maxn],pos[maxn],minn=9e18;
priority_queue<PII,vector<PII>,greater<PII> > Q;
bool judge(LL index)
{
LL sum=0;
for(LL i=1;i<=n;i++)
{
LL left=0,right=a[i]+1;
while(right-left>1)
{
LL mid=left+right>>1ll;
if(F(a[i],mid)>=index)left=mid;
else right=mid;
}
if(F(a[i],left)>=index)pos[i]=left;
else pos[i]=right;
sum+=pos[i];
}
if(sum-k<minn && sum>=k)
{
minn=sum-k;
for(LL i=1;i<=n;i++)ans[i]=pos[i];
}
return sum<k;
}
int main()
{
while(R-L>1)
{
LL mid=L+R>>1ll;
if(judge(mid))R=mid;
else L=mid;
}
judge(L);judge(R);
for(int i=1;i<=n;i++)if(ans[i])Q.push(make_pair(F(a[i],ans[i]),i));
while(minn--)
{
PII now=Q.top();Q.pop();
ans[now.Y]--;
if(ans[now.Y])Q.push(make_pair(F(a[now.Y],ans[now.Y]),now.Y));
}
for(int i=1;i<n;i++)printf("%lld ",ans[i]);
printf("%lld\n",ans[n]);
return 0;
}


### 废话

posted @ 2020-05-08 22:28  小飞淙的云端  阅读(143)  评论(0编辑  收藏