杭电多校第一场补题记录

菜鸟队,只能靠补题了(无奈)。打的时候直接被1004的tle卡爆

1001. Maximum Multiple

打了个一百以内数的因子表,队友看出了规律
n|3的时候就是(n/3)^3
n|2&&n|4 的时候就是(n/2)*(n/4)^2

1003. Triangle Partition

排个序就出来了

1011. Time Zone

把当前时间转化成UTC+0然后模拟一下就出来了

以下的都是赛后补题

1004. Distinct Values

比赛的时候没有注意到m的总和是1e6,所以一直在找o(n)的算法,结果没找到
解法也很简单。先按照区间左排序,枚举每一个区间,用set来维护有那些数字还没有被使用,设置一个右指针表示已经将ans更新到哪个位置,然后将当前区间l到下一个区间l-1的所有ans加入到set中。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct node{
    int l,r;
    bool operator<(const node&x)const{
        if(l==x.l) return r<x.r;
        return l<x.l;
    }
}a[maxn];
set<int>s;
int ans[maxn];
int main()
{
    //freopen("in.txt","r",stdin);
    //reopen("out.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) scanf("%d%d",&a[i].l,&a[i].r);
        sort(a+1,a+m+1);
        for(int i=1;i<=n;i++) s.insert(i),ans[i]=1;
        int r=0;
        for(int i=1;i<=m;i++){
            //这里不能写成if(a[i].r<=r) continue;
            //这样会跳过后面最后那个循环
            if(r<a[i].r)
            for(int j=max(a[i].l,r+1);j<=a[i].r;j++){
                ans[j]=*s.begin();
                s.erase(ans[j]);
            }
            //将对下一个区间可以填的数加到set
            for(int j=a[i].l;j<a[i+1].l;j++){
                s.insert(ans[j]);
            }
            r=max(r,a[i].r);
        }
        printf("%d",ans[1]==0?1:ans[1]);
        for(int i=2;i<=n;i++) printf(" %d",ans[i]==0?1:ans[i]);
        puts("");
        for(int i=0;i<=n;i++)
            ans[i]=0;
        for(int i=0;i<=m;i++)
            a[i].l=a[i].r=0;
    }
    return 0;
}
1002. Balanced Sequence

看了杜教的题解才明白了怎么写
先用栈把每一个字符串处理一下,计算出里面已经匹配括号的数目加到答案中去,然后用一个pair存栈中剩余’)’和‘(‘的数目,然后就是排序。(a, b)表示当前字符串剩余‘)’有a个,’(‘有b个。对于两个(a, b) (c, d)
如果min(b, c)<min(a, d) (这里表示组合后对答案的贡献)则交换,否则,因为两边的括号会被浪费,所以就看那种组合浪费的少

#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
const int maxn=1e5+5;
char s[maxn];
pair<int,int>p[maxn];
stack<char>S;
bool cmp(pair<int,int>& a,pair<int,int>& b)
{
    if(min(a.y,b.x)==min(a.x,b.y)){
        return a.x+b.y<a.y+b.x;//被放在两边的括号相当于是浪费了的
    }else{
        return min(a.y,b.x)>min(a.x,b.y);
    }
    return false;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        int ans=0;
        for(int i=1;i<=n;++i){
            scanf("%s",s);
            for(int j=0;s[j];++j){
                if(S.empty()) S.push(s[j]);
                else{
                    if(s[j]=='(') S.push('(');
                    else{
                        if(S.top()=='(') ans+=2,S.pop();
                        else S.push(')');
                    }
                }
            }
            p[i].x=p[i].y=0;
            while(!S.empty()){
                p[i].x+=S.top()==')';
                p[i].y+=S.top()=='(';
                S.pop();
            }
        }
        sort(p+1,p+n+1,cmp);
        for(int i=1;i<=n;i++){
            //cout<<p[i].x<<' '<<p[i].y<<endl;
            for(int j=1;j<=p[i].x;j++){
                if(S.empty()) S.push(')');
                else{
                    if(S.top()==')') S.push(')');
                    else S.pop(),ans+=2;
                }
            }
            for(int j=1;j<=p[i].y;j++){
                S.push('(');
            }
        }
        while(!S.empty()) S.pop();
        printf("%d\n",ans);
    }
    return 0;
}
1008. RMQ Similar Sequence

看了题解和杜教的视频才抄出来的这份代码。
满足题目中的条件就是两个序列的笛卡尔树同构(菜鸡表示没听过笛卡尔树),然后求概率(完全不会推导)。
了解了一种线性求逆元的骚操作

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
LL mod=1e9+7;
LL inv[maxn];
LL ret;
int a[maxn];
int stk[maxn],l[maxn],r[maxn];
bool vis[maxn];
int n;
int dfs(int u)
{
    int s=1;
    if(l[u]) s+=dfs(l[u]);
    if(r[u]) s+=dfs(r[u]);
    ret=ret*inv[s]%mod;
    return s;
}
void build()
{
    for(int i=0;i<=n;i++) l[i]=r[i]=vis[i]=0;
    for(int i=1,top=0;i<=n;i++){
        int j=top;
        while(j>0&&a[stk[j-1]]<a[i]) --j;
        if(j) r[stk[j-1]]=i;
        if(j<top) l[i]=stk[j];
        top=j;
        stk[top++]=i;
    }
    int root;
    for(int i=1;i<=n;i++){
        vis[l[i]]=true;
        vis[r[i]]=true;
    }
    for(int i=1;i<=n;i++) if(!vis[i]) root=i;
    dfs(root);
}
int main()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    inv[1]=1;
    for(int i=2;i<maxn;i++) inv[i]=inv[mod%i]*(mod-mod/i)%mod;
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        ret=inv[2]*n%mod;
        build();
        printf("%lld\n",ret);
    }
    return 0;   
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值