CF1207

CF1207A

贪心+暴力分讨(看起来背包也行?)

相信大家都会 不细写了

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline 
#define gc getchar
#define pc putchar
const int N=2e5+5;
const int M=1e8+5;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
    int x=0,f=1;char c=gc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    return x*f;
}
inl void write(int x){
    if(x<0){pc('-');x=-x;}
    if(x>9)write(x/10);
    pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a[N],b,p,f,h,c;
signed main(){
    t=read();
    while(t--){
        b=read();p=read();f=read();h=read();c=read();
        if(b/2>=p+f)writel(p*h+f*c);
        else{
            if(h>c){
                if(b/2<p)writel(b/2*h);
                else writel(p*h+(b/2-p)*c);
            }else{
                if(b/2<f)writel(b/2*c);
                else writel(f*c+(b/2-f)*h);
            }
        }
    }
    return 0;
}

CF1207B

这题不限制操作次数 这就变简单很多

考虑一个点能不能改 判一下矩形四个点即可

\(O(nm)\) 暴力枚举 看最后所有1的数量判断是否覆盖全

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline 
#define gc getchar
#define pc putchar
const int N=2e5+5;
const int M=1e8+5;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
    int x=0,f=1;char c=gc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    return x*f;
}
inl void write(int x){
    if(x<0){pc('-');x=-x;}
    if(x>9)write(x/10);
    pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a[55][55],vis[55][55],tot,ans;
vector<pair<int,int>>v;
signed main(){
    n=read();m=read();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            a[i][j]=read();
            tot+=a[i][j];
        }
    }
    for(int i=1;i<n;i++){
        for(int j=1;j<m;j++){
            if(a[i][j]&&a[i][j+1]&&a[i+1][j]&&a[i+1][j+1]){
                if(!vis[i][j])ans++,vis[i][j]=1;
                if(!vis[i+1][j])ans++,vis[i+1][j]=1;
                if(!vis[i][j+1])ans++,vis[i][j+1]=1;
                if(!vis[i+1][j+1])ans++,vis[i+1][j+1]=1;
                v.push_back({i,j});
            }
        }
    }
    if(ans^tot){puts("-1");return 0;}
    writel(v.size());
    for(auto i:v)
        writei(i.first),writel(i.second);
    return 0;
}

CF1207C

简单dp。

\(f_{i,0/1}\) 表示铺设到 \(i\) 管道 不提升/提升的最小花费

初始 \(f_{0,0}=b\ f_{0,1}=2b\) (最开始的柱子)

转移显然:

  • \(i\) 块/第 \(i+1\) 块通车( \(i+1\) 块需要提前提升)
  1. 不提升绝对不行 \(f_{i,0}=inf\)
  2. 提升分两种:
    (1) \(i-1\) 不提升:\(f_{i,1}=f_{i-1,0}+2a+2b\)(两块管子+两节柱子)
    (2) \(i-1\) 提升:\(f_{i,1}=f_{i-1,1}+a+2b\)(一块管子+两节柱子)
  • \(i\) 块/第 \(i+1\) 块均不通车
  1. 不提升:
    (1) \(i-1\) 不提升:\(f_{i,1}=f_{i-1,0}+a+b\)
    (2) \(i-1\) 提升:\(f_{i,1}=f_{i-1,1}+2a+b\)
  2. 提升:
    (1) \(i-1\) 不提升:\(f_{i,1}=f_{i-1,0}+2a+2b\)
    (2) \(i-1\) 提升:\(f_{i,1}=f_{i-1,1}+a+2b\)

答案 \(f_{n,0}\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline 
#define int ll
#define gc getchar
#define pc putchar
const int N=2e5+5;
const int M=1e8+5;
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
    int x=0,f=1;char c=gc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    return x*f;
}
inl void write(int x){
    if(x<0){pc('-');x=-x;}
    if(x>9)write(x/10);
    pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a,b,f[N][2];
char c[N];
signed main(){
    t=read();
    while(t--){
        n=read();a=read();b=read();
        f[0][0]=b;f[0][1]=inf;
        scanf("%s",c+1);
        for(int i=1;i<=n;i++){
            if(c[i]=='1'||c[i+1]=='1'){
                f[i][0]=inf;
                f[i][1]=min(f[i-1][0]+(a<<1)+(b<<1),f[i-1][1]+a+(b<<1));
            }else{
                f[i][0]=min(f[i-1][0]+a+b,f[i-1][1]+(a<<1)+b);
                f[i][1]=min(f[i-1][0]+(a<<1)+(b<<1),f[i-1][1]+a+(b<<1));
            }
        }
        writel(f[n][0]);
    }
    return 0;
}

CF1207D

容斥+计数。

好序列:仅看第一关键字或第二关键字都按升序排序的序列。

求二元组全排列好序列数。

考虑容斥:\(ans=\) 全排列 \(n!\) -按第一维排序有序数量-按第二维排序有序数量+排序后两维都有序数量

显然 求按第一\二维排序有序数量 可以先排序

考虑这个序列:\(1\ 2\ 2\ 3\ 3\ 3\)

假如按第一\二维排序得到序列是这个 数量是几

显然 相同元素随便排 答案都满足 也就是每种元素数量的阶乘 乘起来 所以答案为 \(1!\times 2!\times 3!\)

代码实现可以用双指针 其他方法也行 阶乘可以预处理

那么 求排序后两维都有序数量:以第一维为第一关键字排序、第二维为第二关键字排序

先判第二维是否有序 无序说明 排序后两维都有序数量=0 直接输出

求方案数思路一样:双指针找出第一维元素一样区间 在区间内再次双指针找第二维一样区间 阶乘乘起来即可

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline 
#define int ll
#define gc getchar
#define pc putchar
const int N=3e5+5;
const int M=1e8+5;
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
    int x=0,f=1;char c=gc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    return x*f;
}
inl void write(int x){
    if(x<0){pc('-');x=-x;}
    if(x>9)write(x/10);
    pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a[N],b[N],fac[N],res,ans;
struct node{
    int a,b;
}e[N];
inl bool cmpa(node x,node y){return x.a<y.a;}
inl bool cmpb(node x,node y){return x.b<y.b;}
inl bool cmp(node x,node y){return x.a^y.a?x.a<y.a:x.b<y.b;}
signed main(){
    n=read();fac[0]=fac[1]=1;
    for(int i=2;i<=n;i++)fac[i]=fac[i-1]*i%mod;res=fac[n];
    for(int i=1;i<=n;i++)e[i]={read(),read()};
    sort(e+1,e+n+1,cmpa);
    ans=1;
    for(int l=1,r=1;r<=n;l=r+1,r++){
        while(r+1<=n&&e[r+1].a==e[l].a)r++;
        ans=ans*fac[r-l+1]%mod;
    }
    res=(res-ans+mod)%mod;
    sort(e+1,e+n+1,cmpb);
    ans=1;
    for(int l=1,r=1;r<=n;l=r+1,r++){
        while(r+1<=n&&e[r+1].b==e[l].b)r++;
        ans=ans*fac[r-l+1]%mod;
    }
    res=(res-ans+mod)%mod;
    sort(e+1,e+n+1,cmp);
    for(int i=1;i<n;i++)
        if(e[i].b>e[i+1].b){
            writel(res);return 0;
        }
    ans=1;
    for(int l=1,r=1;r<=n;l=r+1,r++){
        while(r+1<=n&&e[r+1].a==e[l].a)r++;
        for(int p=l,q=l;q<=r;p=q+1,q++){
            while(q+1<=r&&e[q+1].b==e[p].b)q++;
            ans=ans*fac[q-p+1]%mod;
        }
    }
    res=(res+ans)%mod;
    writel(res);
    return 0;
}

CF1207E

交互题格式真烦人

考虑每个二进制位:因为他会在你输出的数里随机选一个 所以要求这些数这一位都相同答案才能确定

这个数最多14位 假如我们每次分别让前7位和后7位相同 刚好能确定这个数

而每次剩下7位 共 \(2^7=128\) 种数 刚好够100个

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline 
#define int ll
#define gc getchar
#define pc putchar
const int N=3e5+5;
const int M=1e8+5;
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
    int x=0,f=1;char c=gc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    return x*f;
}
inl void write(int x){
    if(x<0){pc('-');x=-x;}
    if(x>9)write(x/10);
    pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,a,b,ans;
signed main(){
    a=0;
    for(int i=0;i<=6;i++)a+=(1<<i);
    printf("? ");
    for(int j=1;j<=100;j++)
        writei(a),a+=(1<<7);
    puts("");
    fflush(stdout);
    b=read();
    for(int i=0;i<=6;i++){
        if((b>>i)&1)continue;
        ans+=(1<<i);
    }
    a=0;
    for(int i=7;i<=13;i++)a+=(1<<i);
    printf("? ");
    for(int j=1;j<=100;j++)
        writei(a),a++;
    puts("");
    fflush(stdout);
    b=read();
    for(int i=7;i<=13;i++){
        if((b>>i)&1)continue;
        ans+=(1<<i);
    }
    printf("! ");writel(ans);
    fflush(stdout);
    return 0;
}

CF1207F

根号分治。

对于1操作 显然 \(O(1)\) 可以完成

而二操作 可以理解为将序列分成 \(\dfrac{n}{x}\) 段长为 \(x\) 的段 每段会有一个答案

那么答案数 \(cnt=\dfrac{n}{x}\)

我们发现 \(x>\sqrt n\quad cnt<\sqrt n\) 暴力做

\(x\le \sqrt n\quad cnt\ge\sqrt n\)

发现 \(x\) 很小 可以预处理 \(f_{i,j}\) 表示所有下标模 \(x\) 的结果为 \(y\) 的位置的值之和(就是询问的答案)

在(1)加操作 考虑会造成的贡献 枚举第一维模数\(i\) \(f_{i,x\bmod i}\ \text{+=}\ y\)

总时间复杂度 \(O(n\sqrt n)\)

( \(\sqrt n\) 不要随便取 我开始取的750 直接T飞)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline 
#define int ll
#define gc getchar
#define pc putchar
const int N=5e5+5;
const int M=705;
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const double eps=1e-8;
inl int read(){
    int x=0,f=1;char c=gc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    return x*f;
}
inl void write(int x){
    if(x<0){pc('-');x=-x;}
    if(x>9)write(x/10);
    pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int t,n,m,q,op,a[N],f[M][M],x,y;
signed main(){
    q=read();
    while(q--){
        op=read();x=read();y=read();
        if(op==1){
            a[x]+=y;
            for(int i=1;i<=700;i++)f[i][x%i]+=y;
        }
        if(op==2){
            if(x<=700){writel(f[x][y]);continue;}
            int ans=0;
            for(;y<=5e5;y+=x)ans+=a[y];
            writel(ans);
        }
    }
    return 0;
}

CF1207G

G题是AC自动机 我太菜了不会 学完了补上()

posted @ 2023-10-25 16:42  xiang_xiang  阅读(506)  评论(0编辑  收藏  举报