CF1153

CF1153A

按题意模拟即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define inl inline
const int N=3e7+5;
const int M=1e5+5;
const int mod=1e7+9;
const int inf=0x3f3f3f3f;
inl int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
inl void write(int x){
    if(x<0){x=-x;putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
inl void writei(int x){write(x);putchar(' ');}
inl void writel(int x){write(x);putchar('\n');}
int n,t,s,d,ans=inf,res;
signed main(){
    n=read();t=read();
    for(int i=1;i<=n;i++){
        s=read();d=read();
        while(s<t)s+=d;
        if(s<ans)ans=s,res=i;
    }
    writel(res);
    return 0;
}

CF1153B

诈骗题。想了 \(inf\) 种阶乘做法,发现对每个位置的答案就是该行/列的最大值取 \(\min\) /fn

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define inl inline
const int N=1e2+5;
const int M=1e5+5;
const int mod=1e7+9;
const int inf=0x3f3f3f3f;
inl int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
inl void write(int x){
    if(x<0){x=-x;putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
inl void writei(int x){write(x);putchar(' ');}
inl void writel(int x){write(x);putchar('\n');}
int n,m,h,a[N],b[N],vis[105][105];
signed main(){
    n=read();m=read();h=read();
    for(int i=1;i<=m;i++)a[i]=read();
    for(int i=1;i<=n;i++)b[i]=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(read())vis[i][j]=min(b[i],a[j]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++)
            writei(vis[i][j]);
        puts("");
    }
    return 0;
}

CF1153C

黄题调不出来。

显然的贪心做法:尽量在前面放左括号。

\(ans\) 表示 \([1,i]\) 中左括号比右括号多的个数。

\(n-1\) 位置要求 \(ans\le 0\)\(n\) 位要求 \(ans=0\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define inl inline
const int N=1e6+5;
const int M=1e5+5;
const int mod=1e7+9;
const int inf=0x3f3f3f3f;
inl int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
inl void write(int x){
    if(x<0){x=-x;putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
inl void writei(int x){write(x);putchar(' ');}
inl void writel(int x){write(x);putchar('\n');}
int n,ans[N];
string s;
signed main(){
    n=read();cin>>s;
    if(n&1){puts(":(");return 0;}
    int cnt=n>>1;
    for(int i=0;i<=n-1;i++){
        if(s[i]=='(')ans[i]++,cnt--;
        if(s[i]==')')ans[i]--;
    }
    if(cnt<0){puts(":(");return 0;}
    for(int i=0;i<=n-2;i++){
        if(s[i]=='?')
            if(cnt)s[i]='(',ans[i]++,cnt--;
            else s[i]=')',ans[i]--;
        if(i)ans[i]+=ans[i-1];
        if(ans[i]<=0){puts(":(");return 0;}
    }
    if(s[n-1]=='?')
        if(cnt)s[n-1]='(',ans[n-1]++,cnt--;
        else s[n-1]=')',ans[n-1]--;
    ans[n-1]+=ans[n-2];
    if(ans[n-1])puts(":(");
    else cout<<s<<endl;
    return 0;
}

CF1153D

神仙树形dp。

先举个栗子:假如说一个点连着5个叶子 那么它的 \(\min\) 一定为1 \(\ \max\) 一定为5

对于 \(\min\)\(\max\) 操作 我们能发现一些性质:

\(\min\) 操作 该节点答案相当于叶子总数量-所有叶子数+1(因为这样只能从大到小排了) 相当于取到所有叶子

\(\max\) 操作 该节点答案则为叶子总数量 这时我们发现它相当只取一个叶子

\(f_x\) 表示节点 \(x\) 连接的叶子总数量 每个节点的答案 \(ans\) 为 子树内所有叶子数-\(f_x+1\)

那么有如下转移:

\[f_x=\begin{cases}\sum_y f_y&a_x=\min\\\min(f_y)&a_x=\max\end{cases} \]

解释一下 \(\min\) 操作 相当于儿子连的所有叶子 从大到小排

\(\max\) 操作 我们只连一个儿子 那么自然取最少的连了

边界条件:叶子节点 \(f_x=1\)

懒得建树 代码为非递归写法

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define inl inline
const int N=1e6+5;
const int M=1e5+5;
const int mod=1e7+9;
const int inf=0x3f3f3f3f;
inl int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
inl void write(int x){
    if(x<0){x=-x;putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
inl void writei(int x){write(x);putchar(' ');}
inl void writel(int x){write(x);putchar('\n');}
int n,a[N],fa[N],f[N],son[N],k,q[N],h,t=1;
string s;
signed main(){
    n=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++)f[i]=a[i]*inf;
    for(int i=2;i<=n;i++)fa[i]=read();
    for(int i=2;i<=n;i++)son[fa[i]]++;
    for(int i=1;i<=n;i++)k+=!son[i];
    for(int i=1;i<=n;i++)if(!son[i])q[++h]=i,f[i]=1;
    while(h>=t){
        int x=q[t++];
        if(a[fa[x]])f[fa[x]]=min(f[fa[x]],f[x]);
        else f[fa[x]]+=f[x];
        if(!--son[fa[x]])q[++h]=fa[x];
    }
    writel(k-f[1]+1);
    return 0;
}

CF1153E

交互题。

一个重要的性质:交互的答案如果为奇数 那么说明链的两个端点一个在矩形内 一个在矩形外

那么我们就可以用这个判定出每一行每一列是否存在一个端点 如果找到了二分确定具体位置

最多交互次数:\(n\times n\times \left\lceil\\log n\right\rceil\times \left\lceil\\log n\right\rceil\)

\(n=1000\) 时 次数为 \(2020\)

然后刚好多一。

我们在判行和列的时候 发现如果前 \(n-1\) 个里面找到了一个端点 那么 \(n\) 一定为另一个端点

那么我们的交互次数就只有 \(2018\) 次了

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define inl inline
const int N=1e6+5;
const int M=1e5+5;
const int mod=1e7+9;
const int inf=0x3f3f3f3f;
inl int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
inl void write(int x){
    if(x<0){x=-x;putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
inl void writei(int x){write(x);putchar(' ');}
inl void writel(int x){write(x);putchar('\n');}
int n,x,res;
vector<int>v;
signed main(){
    n=read();
    for(int i=1;i<n;i++){
        printf("? %d %d %d %d\n",i,1,i,n);
        fflush(stdout);
        x=read();
        if(x&1)v.push_back(i);
    }
    if(v.size()==1)v.push_back(n);
    if(v.empty()){
        for(int i=1;i<n;i++){
            printf("? %d %d %d %d\n",1,i,n,i);
            fflush(stdout);
            x=read();
            if(x&1)v.push_back(i);
        }
        if(v.size()==1)v.push_back(n);
        int l=1,r=n,ans;
        while(l<=r){
            int mid=l+r>>1;
            printf("? %d %d %d %d\n",l,v[0],mid,v[0]);
            fflush(stdout);
            x=read();
            if(x&1)ans=mid,r=mid-1;
            else l=mid+1;
        }
        res=ans;
        l=1,r=n;
        while(l<=r){
            int mid=l+r>>1;
            printf("? %d %d %d %d\n",l,v[1],mid,v[1]);
            fflush(stdout);
            x=read();
            if(x&1)ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("! %d %d %d %d\n",res,v[0],ans,v[1]);
        fflush(stdout);
        return 0;
    }
    int l=1,r=n,ans;
    while(l<=r){
        int mid=l+r>>1;
        printf("? %d %d %d %d\n",v[0],l,v[0],mid);
        fflush(stdout);
        x=read();
        if(x&1)ans=mid,r=mid-1;
        else l=mid+1;
    }
    res=ans;
    l=1,r=n;
    while(l<=r){
        int mid=l+r>>1;
        printf("? %d %d %d %d\n",v[1],l,v[1],mid);
        fflush(stdout);
        x=read();
        if(x&1)ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("! %d %d %d %d\n",v[0],res,v[1],ans);
    fflush(stdout);
    return 0;
}

CF1153F

不会期望。

posted @ 2023-11-03 11:08  xiang_xiang  阅读(25)  评论(0)    收藏  举报