ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Atcoder 233

2022-03-05 17:35:52  阅读:157  来源: 互联网

标签:Atcoder le return int void 233 dp define


Atcoder 233

\(D.\)Count Intervaul

题意

给定一个长度为\(N\)的序列\(A=\{A_1,A_2,...,A_n\}\)和一个整数\(K\),问有多少个数对\((l,r)\),\(st.\) \(\sum_{i=l}^rA_i=K\)

\(1\le N\le2\times10^5\) \(-10^9\le A_i \le 10^9\) \(1\le K\le10^{18}\)

Sol

很容易想到前缀和,但求完前缀和之后如果暴力枚举左右端点\(O(n^2)\)无法承受

由于要求\(S[r]-s[l-1]=K\),转换一下,对于每个\(r\)求有多少个\(l\)满足要求,即求\(S[r]-k\)有多少个,用\(map\) 记录一下即可 \(O(nlogn)\)

#include <bits/stdc++.h>
#define ll long long
#define inf 0x7f7f7f7fll
#define fi first
#define se second
#define mod 998244353
#define pb push_back
using namespace std;

template <typename T> void rd (T &x)
{
    x=0;int f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-') f=-1;s=getchar();}
    while(s>='0'&&s<='9') x=x*10+(s^48),s=getchar();
    x*=f;
}
template <typename T> void chkMax(T &x, T y) { if (y > x) x = y; }
template <typename T> void chkMin(T &x, T y) { if (y < x) x = y; }

const int N=2e5+10;
int a[N];
ll s[N];
map<ll,ll>hs;
int main()
{
    int n;
    ll k;
    rd(n),rd(k);
    for(int i=1;i<=n;i++) rd(a[i]);
        for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
         hs[s[i-1]]++;
         ans+=hs[s[i]-k];
    }
    cout<<ans<<endl;
    return 0;
}

\(F.\)Swap and Sort

题意

有一个关于\((1,2,...,N)\)的排列\(P=(P_1,P_2,...,P_n)\)

现在有\(M\)中操作:第\(i\)种操作是交换\(P\)的第\(a_i\)和第\(b_i\)个元素

问是否可以操作不大于\(5\times10^5\)次使得\(P\)变为\((1,2,...,N)\)

如果可以输出操作次数和操作顺序,如果不可以输出-1

\(1\le N \le5000\) \(1\le M\le min(2\times10^5,\frac{N(N-1)}{2})\)

\((a_i,b_i)!=(a_j,b_j)\) if \(i!=j\)

Sol

对于这种全排序序列的问题,很常见的一个想法就是构造连通图

对于所有种类的操作,将它们用并查集划分成一个个连通块

然后判断一遍\(P_i\)是否和\(i\)在一个连通块内,如果不在,说明\(P_i\)和\(i\)无法通过交换的到,输出\(-1\)

否则,说明有解,那么从一个没有被访问过且点度为\(1\)的数\(P_i\)开始复位并删点,如果他可以通过这些操作到达\(i\),说明这条寻找路径上的所有交换操作都可以使用,加入答案中即可,等价于在生成树上找。

由于最多交换\(999+998+...+2+1=499500\)次,所有有解的话一定满足条件

#include <bits/stdc++.h>
#define ll long long
#define inf 0x7f7f7f7fll
#define fi first
#define se second
#define mod 998244353
#define pb push_back
using namespace std;

template <typename T> void rd (T &x)
{
    x=0;int f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-') f=-1;s=getchar();}
    while(s>='0'&&s<='9') x=x*10+(s^48),s=getchar();
    x*=f;
}
template <typename T> void chkMax(T &x, T y) { if (y > x) x = y; }
template <typename T> void chkMin(T &x, T y) { if (y < x) x = y; }

const int N=1005;
int p[N],fa[N],st[N];
int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
struct edges{int v,id;};
vector<edges>e[N];
vector<int>ans;
bool dfs2(int u,int to,int f)
{
     if(p[u]==to) return true;
     for(auto t:e[u])
     {
        int v=t.v,id=t.id;
        if(v==f) continue;
        if(dfs2(v,to,u))
        {
            swap(p[u],p[v]);
            ans.pb(id);
            return true;
        }
     }
     return false;
}
void dfs1(int u) //从点度为1的点开始搜
{
    st[u]=1;
    for(auto t:e[u])  
    {
        int v=t.v;
        if(st[v]) continue;
        dfs1(v);
    }
    dfs2(u,u,-1);
}
int main()
{
    int n;
    rd(n);
    for(int i=1;i<=n;i++) rd(p[i]),fa[i]=i;
    int m;
    rd(m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        rd(x),rd(y);
        int fx=find(x),fy=find(y);
        if(fx!=fy)
        {
            fa[fx]=fy;
            e[x].pb({y,i});
            e[y].pb({x,i});
        }
    }
    for(int i=1;i<=n;i++)
    {
        int fx=find(p[i]),fy=find(i);
        if(fx!=fy)
        {
            puts("-1");
            return 0;
        }
    }
    for(int i=1;i<=n;i++)
    if(!st[i]) dfs1(i);
    printf("%d\n",ans.size());
    for(auto id:ans) printf("%d ",id);
        return 0;
}

\(G.\)Strongest Takahashi

题意

给定一个\(N\times N\)的网格图,里面有若干个障碍#,每次可以选择一个整数\(D\)(\(1\le D\le N\)),然后选择一个\(D\times D\)的区域把里面的障碍都消掉,每次消耗为\(D\),请问最少需要消耗多少可以把障碍全部消完。

\(1\le N \le 50\)

Sol

定义\(dp[x_1][y_1][x_2][y_2]\)为消掉以(\(x_1,y_1\))为左上角,以(\((x_2,y_2)\))为右下角的矩形内的障碍最少需要的消耗。

一个\(A\times B\)的矩形的最大消耗为\(max(A,B)\)

可以考虑将一个矩形按划分方式递推

1.横着划分:\(dp[x_1][y_1][x_2][y_2]=min(dp[x_1,y_1,x_2,y_2],dp[x_1][y_1][k][y_2]+dp[k+1][y_1][x_2][y_2])\) \(x_1\le k \lt x_2\)

2.竖着划分:\(dp[x_1][y_1][x_2][y_2]=min(dp[x_1][y_1][x_2][y_2],dp[x_1][y_1][x_2][k]+dp[x_1][k+1][x_2][y_2])\) \(y_1 \le k \lt y_2\)

#include <bits/stdc++.h>
#define ll long long
#define inf 0x7f7f7f7fll
#define fi first
#define se second
#define mod 998244353
#define pb push_back
using namespace std;

template <typename T> void rd (T &x)
{
    x=0;int f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-') f=-1;s=getchar();}
    while(s>='0'&&s<='9') x=x*10+(s^48),s=getchar();
    x*=f;
}
template <typename T> void chkMax(T &x, T y) { if (y > x) x = y; }
template <typename T> void chkMin(T &x, T y) { if (y < x) x = y; }

char g[55][55];
int dp[55][55][55][55];
int dfs(int x1,int y1,int x2,int y2)
{
    int &t=dp[x1][y1][x2][y2];
    
    if(t!=-1) return t;
    if(x1==x2&&y1==y2) return g[x1][y1]=='#';
    t=max(x2-x1+1,y2-y1+1);
    for(int k=x1;k<x2;k++)
    t=min(t,dfs(x1,y1,k,y2)+dfs(k+1,y1,x2,y2));
    for(int k=y1;k<y2;k++)
    t=min(t,dfs(x1,y1,x2,k)+dfs(x1,k+1,x2,y2));
    return t;
}
int main()
{
    memset(dp,-1,sizeof dp);
    int n;
    rd(n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            cin>>g[i][j];
    printf("%d\n",dfs(1,1,n,n));
    return 0;
}

\(Ex.Manhattan Christmas Tree\)

题意

在二维平面上给定\(N\)个点,有\(Q\)个询问,每次询问给定一个点\((a_i,b_i)\)和\(K_i\),问这\(N\)个点距离\((a_i,b_i)\)第\(K_i\)近的距离是多少

距离的计算是曼哈顿距离.

所有数据的范围都是\(1\le data \le 10^5\)

Sol

前置知识:

假设\(A(x_1,y_1),B(x_2,y_2)\)

曼哈顿距离:\(d1=|x_1-x_2|+|y_1-y_2|\)

切比雪夫距离:\(d_2=max(|x_1-x_2|,|y_1-y_2|)\)

曼哈顿距离到切比雪夫距离:\((x,y)->(x+y,x-y)\) 可以看做把坐标系旋转\(45^{。}\)

推导:

(1) \(d_1=x_1-x_2+y_1-y_2\) (2) \(d_1=x_1-x_2+y_2-y_1\) (3) \(d_1=x_2-x_1+y_1-y_2\) (4) \(d_1=x_2-x_1+y_2-y_1\)

求这4中情况中最大的

其中(1)(4)得到\(|(x_1+y_1)-(x_2+y_2)|\) (2)(3)得到\(|(x_1-y_1)-(x_2-y_2)|\)

最大就是\(max(|(x_1+y_1)-(x_2+y_2)|,|(x_1-y_1)-(x_2-y_2)|)\)

最小值同理

切比雪夫距离到曼哈顿距离转化:\((x,y)->(\frac{x+y}{2},\frac{x-y}{2})\)

于是对每个询问就可以二分一下第\(k\)近的距离,\(check\)就是查询有多少个点到\((a_i,b_i)\)的切比雪夫距离\(\le\)二分距离\(mid\),这就是一个二维数点问题,可以用树状数组或者主席树解决。这里采用树状数组。

![屏幕截图 2022-01-11 173335](C:\Users\asus\Pictures\Saved Pictures\屏幕截图 2022-01-11 173335.jpg)

![屏幕截图 2022-01-11 173335](C:\Users\asus\Pictures\Saved Pictures\屏幕截图 2022-01-11 173352.jpg)

#include <bits/stdc++.h>
#define ll long long
#define inf 0x7f7f7f7fll
#define fi first
#define se second
#define mod 998244353
#define pb push_back
using namespace std;

template <typename T> void rd (T &x)
{
    x=0;int f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-') f=-1;s=getchar();}
    while(s>='0'&&s<='9') x=x*10+(s^48),s=getchar();
    x*=f;
}
template <typename T> void chkMax(T &x, T y) { if (y > x) x = y; }
template <typename T> void chkMin(T &x, T y) { if (y < x) x = y; }

const int N=2e5+10;
struct Point{
  int x,y;
  bool operator < (const Point &t) const
  {
    return y<t.y;
  }
}p[N];
vector<int>tr[N];
int lowbit(int x){return x&-x;}
void add(int x,int y)
{
  for(int pos=x;pos<N;pos+=lowbit(pos))
    tr[pos].pb(y);
}
int sum(int x,int y1,int y2)
{
  int res=0;
  for(int pos=x;pos;pos-=lowbit(pos))
  {
    res+=upper_bound(tr[pos].begin(),tr[pos].end(),y2)-lower_bound(tr[pos].begin(),tr[pos].end(),y1);
  }
  return res;
}
int query(int x1,int x2,int y1,int y2)
{
    //边界特判
  x1=max(x1,1);
  x2=max(x2,0);
  x1=min(x1,N-1);
  x2=min(x2,N-1);
  return sum(x2,y1,y2)-sum(x1-1,y1,y2); 
}
bool check(int a,int b,int k,int mid)  //二分距离,如果在这个范围内的点数大于k说明距离大了
{
  int x=a+b+1;
  int y=a-b+1;
  return query(x-mid,x+mid,y-mid,y+mid)>=k;
}
int n,t;
int main()
{
  rd(n);
  for(int i=1;i<=n;i++)
  {
    int x,y;
    rd(x),rd(y);
    p[i].x=x+y+1,p[i].y=x-y+1;
  }
  sort(p+1,p+1+n);
  for(int i=1;i<=n;i++)
    add(p[i].x,p[i].y);
  rd(t);
  while(t--)
  {
    int a,b,k;
    rd(a),rd(b),rd(k);
    int l=0,r=2e5+10;
    while(l<r)
    {
      int mid=l+r>>1;
      if(check(a,b,k,mid)) r=mid;
      else l=mid+1;
    }
    cout<<r<<'\n';
  }
  return 0;
}

标签:Atcoder,le,return,int,void,233,dp,define
来源: https://www.cnblogs.com/Arashimu0x7f/p/15968688.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有