首页 > 其他分享 >ABC269

ABC269

时间:2022-09-18 11:12:51浏览次数:97  
标签:int sum namespace cin using include ABC269

D

Content

给你若干个点和相邻点的定义,问你图中有几个连通块。

Sol

连通用并查集维护,就是这里的相邻有点怪。

Code
#include<bits stdc++.h="">
using namespace std;
const int _=1005;
int n;
int a[_],b[_];
int ff[_];
int find(int x){return ff[x]==x?x:ff[x]=find(ff[x]);}
bool check(int x1,int y1,int x2,int y2){
    if(x1&lt;x2) swap(x1,x2),swap(y1,y2);
    else if(x1==x2&amp;&amp;y1&lt;y2) swap(y1,y2);
    if(abs(x1-x2)+abs(y1-y2)&lt;=2&amp;&amp;0&lt;=x1-x2&amp;&amp;x1-x2&lt;2&amp;&amp;0&lt;=y1-y2&amp;&amp;y1-y2&lt;2) return 1;
    return 0;
}
int main(){
    cin&gt;&gt;n;
    for(int i=1;i&lt;=n;++i) cin&gt;&gt;a[i]&gt;&gt;b[i],ff[i]=i;
    for(int i=1;i&lt;=n;++i){
        for(int j=1;j&lt;=n;++j){
            if(i==j) continue;
            if(check(a[i],b[i],a[j],b[j])){
                // cout&lt;&lt;i&lt;&lt;' '&lt;&lt;j&lt;&lt;endl;
                int x=find(i),y=find(j);
                if(x==y) continue;
                ff[x]=y;
            }
        }
    }
    int ans=0;
    for(int i=1;i&lt;=n;++i) if(ff[i]==i) ++ans;
    cout&lt;&lt;ans&lt;&lt;endl;
    return 0;
}
</bits>

E

Content

交互题,有一个 \(n\times n\) 的棋盘,上面已经摆了 \(n-1\) 个象棋的车(即每行每列都至多有一个车),你每次能询问一个矩形区域里面有多少车,问再摆一个车能放在哪个格子里。

Sol

行和列是独立的,考虑先做行,相当于是找一个唯一的权是0的行,二分一个 \(mid\),询问行列范围 \(1\sim mid,1\sim n\),找到第一个结果为 \(mid-1\) 的行即为答案。列做法同理。

Code
#include<bits stdc++.h="">
using namespace std;
int n;
int ask(int l,int r,int x,int y){
    cout&lt;&lt;"? "&lt;&lt;l&lt;&lt;' '&lt;&lt;r&lt;&lt;' '&lt;&lt;x&lt;&lt;' '&lt;&lt;y&lt;&lt;endl;
    int t; cin&gt;&gt;t;
    return t;
}
int main(){
    cin&gt;&gt;n;
    int l=1,r=n,ansl=-1;
    while(l&lt;=r){
        int mid=l+r&gt;&gt;1;
        if(ask(1,mid,1,n)&lt;mid) ansl=mid,r=mid-1;
        else l=mid+1;
    }
    int ansr=-1;
    l=1,r=n;
    while(l&lt;=r){
        int mid=l+r&gt;&gt;1;
        if(ask(1,n,1,mid)&lt;mid) ansr=mid,r=mid-1;
        else l=mid+1;
    }
    cout&lt;&lt;"! "&lt;&lt;ansl&lt;&lt;' '&lt;&lt;ansr;
    return 0;
}
</bits>

F

Content

有 \(n\times m\) 的网格,每个格子上的数为 \((i-1)\times m+j\),当 \(i+j\) 为奇数时,格子上的数会变为 \(0\),询问一个矩形,问这个矩形包含元素的和。

Sol

分类讨论:

  • \(i\) 为奇,\(j\) 为偶
  • \(i\) 为偶,\(j\) 为奇

推式子 \(\sum\limits_i\sum\limits_j m(i-1)+j = \sum\limits_i(cnt_j\cdot m(i-1)+\sum\limits_j)=(cnt_j\cdot m\sum\limits_i i) + (cnt_i\sum\limits_j)\)

\(cnt_i\) 表示 \(i\) 有多少项,\(j\) 同理。

然后直接等差数列求和即可。

Code
#include<bits stdc++.h="">
#define int long long
using namespace std;
const int mod=998244353,i2=499122177;
int n,m,q;
signed main(){
    ios::sync_with_stdio(0); cin.tie(0);
    cin&gt;&gt;n&gt;&gt;m&gt;&gt;q;
    while(q--){
        int a,b,c,d; cin&gt;&gt;a&gt;&gt;b&gt;&gt;c&gt;&gt;d;
        int x,y,cnt1,D,DD,cnt2,res=0;
        //case 1
        if(a%2==0) x=a; else x=a-1;
        if(b%2==0) y=b-2; else y=b-1;
        if(x&lt;=y) cnt1=(x+y)*((y-x)*i2%mod+1)%mod*i2%mod,D=(y-x)*i2%mod+1; else cnt1=D=0;
        if(c%2==0) x=c+1; else x=c;
        if(d%2==0) y=d-1; else y=d;
        if(x&lt;=y) cnt2=(x+y)*((y-x)*i2%mod+1)%mod*i2%mod,DD=(y-x)*i2%mod+1; else cnt2=DD=0;
        res=(res+(cnt1*m%mod*DD%mod+cnt2*D%mod)%mod)%mod;
        //case 2
        if(a%2==0) x=a-1; else x=a;
        if(b%2==0) y=b-1; else y=b-2;
        if(x&lt;=y) cnt1=(x+y)*((y-x)*i2%mod+1)%mod*i2%mod,D=(y-x)*i2%mod+1; else cnt1=D=0;
        if(c%2==0) x=c; else x=c+1;
        if(d%2==0) y=d; else y=d-1;
        if(x&lt;=y) cnt2=(x+y)*((y-x)*i2%mod+1)%mod*i2%mod,DD=(y-x)*i2%mod+1; else cnt2=DD=0;
        res=(res+(cnt1*m%mod*DD%mod+cnt2*D%mod)%mod)%mod;
        cout&lt;&lt;res&lt;&lt;endl;
    }
    return 0;
}
</bits>

G

Content

有 \(n\) 张正反两面写有数字的卡片,初始时全是正面,正反两面数字之和 \(M\le 2e5\),你可以翻转这 \(n\) 张卡片的任意一张。对于每个 \(k \in [0,m]\),问当前朝上的数字之和等于 \(k\) 时的最少翻转数,不能表示就为 \(-1\)。

Sol

每次翻转的增量为 \(-a_i+b_i\),先考虑增量为正数情况,因为 \(\sum -a_i+b_i \le M\) 所以不同的增量个数至多 \(\sqrt M\) 个,因为等差数列显然为最有情况,有求和公式:\(\sqrt M (\sqrt M +1)/2 = M\),增量为负类似,全部乘个 \(-1\) 就是正数了。所以不同的增量个数为 \(2 \sqrt M\)。

所以我们处理出不同的增量这个增量出现的个数,相当于是选若干个物品使得体积为 \(k\),多重背包问题,优化一下就行了。这里二进制拆分法要快于单调队列法,因为可以证明当 \(\sum a_i\le n\) 时,\(\sum a_i\log a_i\) 是 \(O(n\sqrt n)\) 级别的(证明可以看官方题解)。

二进制拆分
#include<bits stdc++.h="">
#include<ext assoc_container.hpp="" pb_ds="">
#include<ext hash_policy.hpp="" pb_ds="">
using namespace __gnu_pbds;
using namespace std;
const int _=4e5+5,N=2e5;
int n,m;
int a[_],b[_],f[_],S;
gp_hash_table&lt;int,int&gt; M;
vector&lt;pair&lt;int,int&gt;&gt; V;
int main(){
    ios::sync_with_stdio(0); cin.tie(0);
    cin&gt;&gt;n&gt;&gt;m;
    for(int i=1;i&lt;=n;++i) cin&gt;&gt;a[i]&gt;&gt;b[i],++M[b[i]-a[i]],S+=a[i];
    for(auto x:M){
        int i;
        // cout&lt;&lt;x.first&lt;&lt;' '&lt;&lt;x.second&lt;&lt;endl;
        for(i=1;i&lt;=x.second;i&lt;&lt;=1) V.push_back({i*x.first,i});//,cout&lt;&lt;i&lt;&lt;' ';
        V.pop_back();
        V.push_back({(x.second-(i&gt;&gt;1)+1)*x.first,x.second-(i&gt;&gt;1)+1});
        // cout&lt;&lt;x.second-(i&gt;&gt;1)+1&lt;&lt;endl;
    }
    memset(f,0x3f,sizeof f);
    f[S+N]=0;
    for(auto xx:V){
        int x=xx.first,y=xx.second;
        if(x&gt;0){
            for(int j=m;j&gt;=-m+x;--j){
                f[j+N]=min(f[j+N],f[j-x+N]+y);
            }
        }
        else{
            for(int j=-m;j-x&lt;=m;++j){
                f[j+N]=min(f[j+N],f[j-x+N]+y);
            }
        }
    }
    for(int i=0;i&lt;=m;++i){
        if(f[i+N]==0x3f3f3f3f) cout&lt;&lt;-1&lt;&lt;endl;
        else cout&lt;&lt;f[i+N]&lt;&lt;endl;
    }
    return 0;
}
</ext></ext></bits>
单调队列
#include<bits stdc++.h="">
#include<ext assoc_container.hpp="" pb_ds="">
#include<ext hash_policy.hpp="" pb_ds="">
using namespace __gnu_pbds;
using namespace std;
const int _=4e5+5,N=2e5;
int n,m;
int a[_],b[_],f[_],q[_][2],l,r,S;
gp_hash_table&lt;int,int&gt; M;
vector&lt;pair&lt;int,int&gt;&gt; V;
int main(){
    ios::sync_with_stdio(0); cin.tie(0);
    cin&gt;&gt;n&gt;&gt;m;
    for(int i=1;i&lt;=n;++i) cin&gt;&gt;a[i]&gt;&gt;b[i],++M[b[i]-a[i]],S+=a[i];
    memset(f,0x3f,sizeof f);
    f[S+N]=0;
    for(auto xx:M){
        int x=xx.first,y=xx.second;
        if(x&gt;0){
            for(int j=0;j&lt;x;++j){
                l=1,r=0;
                q[1][0]=-114514191;
                for(int k=0;k*x+j&lt;=m+N;++k){
                    int b=f[k*x+j]-k;
                    while(l&lt;=r&amp;&amp;q[r][0]&gt;b) --r;
                    q[++r][0]=b,q[r][1]=k;
                    while(q[l][1]+y&lt;k) ++l;
                    f[k*x+j]=q[l][0]+k;
                }
            }
        }
        else{
            for(int j=0;j&gt;x;--j){
                l=1,r=0;
                q[1][0]=-114514191;
                for(int k=0;m+N+k*x+j&gt;=0;++k){
                    int b=f[m+N+k*x+j]-k;
                    while(l&lt;=r&amp;&amp;q[r][0]&gt;b) --r;
                    q[++r][0]=b,q[r][1]=k;
                    while(q[l][1]+y&lt;k) ++l;
                    f[m+N+k*x+j]=q[l][0]+k;
                }
            }
        }
    }
    for(int i=0;i&lt;=m;++i){
        if(f[i+N]==0x3f3f3f3f) cout&lt;&lt;-1&lt;&lt;endl;
        else cout&lt;&lt;f[i+N]&lt;&lt;endl;
    }
    return 0;
}
</ext></ext></bits>

更简单的场了,F 以前都是送的,加了350真好。

标签:int,sum,namespace,cin,using,include,ABC269
From: https://www.cnblogs.com/Quick-Kk/p/ABC269.html

相关文章