24ICPC成都站补题

思路参考1
思路参考2
原题链接

A 构造

cpp 复制代码
void solve(){
    string s;cin>>s;
    int n=s.size();
    if(n<5)rno;//#define rno return cout<<"No"<<endl,void()
    s=' '+s;
    int hd=0,fg=0;
    vector<int>t,h;
    vector<pii>ans;
    reforr(i,1,n){
        if(fg==0){
            hd+=(s[i]=='>');//hd匹配头上的>>>
            if(s[i]=='-'){
                if(hd<3)rno;
                fg=1;
            }
        }else if(s[i]=='>')t.push_back(i);
    }
    //s[1]一定要是>  否则会有->-->>>的不合法情况
    if(s[1]=='-'||fg==0||t.size()==0){
        rno;//#define rno return cout<<"No"<<endl,void()
    }

    int bg=n-hd+3;
    reforr(i,bg,n)h.push_back(i);//头顶从大到小

    sort(t.begin(),t.end());//尾巴从小到大
    if(h.size()>t.size())swap(h,t);

    int sz=h.size(),pid=0;
    for(auto i:t){
        ans.push_back({min(i,h[pid]),max(i,h[pid])});
        if(pid+1<sz)pid++;
    }
    cout<<"Yes "<<ans.size()<<endl;
    for(auto x:ans){
        cout<<x.fir<<' '<<x.sec-x.fir+1<<endl;
    }
}

G 位运算 思维

只有三种运算x&y x^y x|y

每一位上01状态不同会有不同的结果,所以把xy的每一位组合在一起看结果能得到什么样的数

cpp 复制代码
void solve(){
    int n;cin>>n;
	set<int>s;
	vector<int>a(n+1);
	forr(i,1,n)cin>>a[i];
	//废案 一开始想到了暴力bfs
	// forr(i,2,n-1){
	// 	s.insert(a[i+1]&a[i]);
	// 	s.insert(a[i+1]|a[i]);
	// 	s.insert(a[i+1]^a[i]);
	// }
	s.insert(0);
	forr(i,1,n-1){
		//b11结果是x&y的该位结果  b10+b01是^ b10+b11+b01是|
		int b11,b10,b01;b11=b01=b10=0;
		//计算每一位情况
		reforr(j,0,31){
			int bnow=a[i]&(1<<j),bnxt=a[i+1]&(1<<j);
			if(bnow&&bnxt)b11|=bnow;
			else if(bnow)b10|=bnow;
			else if(bnxt)b01|=bnxt;
		}
		//x=now  y=nxt
		//b10:x^y&x->(b10+b01-b01)  b01:x^y&y
		//b10+b11:x  b01+b11:y
		vector<int>tp={b11,b10+b01,b11+b01+b10,b10,b01,b10+b11,b01+b11};
		for(auto t:tp)s.insert(t);
	}
	cout<<s.size()<<endl;
}

I 线段树 gcd

把数组分成长度为k的等长的非递减段(最后一段可以<=k),最后求合法k的个数

最大的k就是每个非递减段长度的gcd

  • 这里可以直接用分段处的下标 因为gcd(a,b-a)=gcd(a,b)

如 2 3 |1 4 5 7 | 8 9,k=2

分段下标i=2 6 8

每个等长非递减段又可以分,分解成k的因数长

有多个询问,使用线段树优化

cpp 复制代码
const int N=2e5+4;
struct node
{  //区间   值
    int l,r,val;
};
struct segmentr{
    node tr[N<<2];
    void build(int pos,int l,int r){
        tr[pos]={l,r,0};
        if(l!=r){
            int mid=(l+r)>>1;
            build(pos<<1,l,mid);
            build(pos<<1|1,mid+1,r); 
        }
    }
    void pushup(int pos){
        tr[pos].val=__gcd(tr[pos<<1].val,tr[pos<<1|1].val);//更新大区间的gcd
    }
    void modify(int pos,int aim,int val){
        if(tr[pos].l==tr[pos].r){tr[pos].val=val;return;}
        int mid=(tr[pos].l+tr[pos].r)>>1;
        if(mid>=aim)modify(pos<<1,aim,val);
        else modify(pos<<1|1,aim,val);
        pushup(pos);
    }
}t;
int cnt[N];//因数个数
//直接对分界点位置i进行gcd 因为gcd(a,b,c)=gcd(a,b-a,c-b) 线性组合后gcd不变
void solve(){
    int n,q;cin>>n>>q;
    t.build(1,1,n);
    vector<int>a(n+2);
    forr(i,1,n){
        cin>>a[i];
    }
    a[n+1]=0;
    forr(i,1,n-1){//最后一个点不必加进去 因为长度不一定是k
        if(a[i]>a[i+1]){
            t.modify(1,i,i);//记录递增段最后的一个点 递减分界点
        }
        else t.modify(1,i,0);
    }

    int ans=t.tr[1].val;//所有断点下标的gcd
    if(ans==0)cout<<n<<endl;//a全为0 最长段是n
    else cout<<cnt[ans]<<endl;//注意最后要输出合规长度的数量

    forr(i,1,q){
        int p,v;cin>>p>>v;
        a[p]=v;
        if(p>1&&a[p-1]>a[p])t.modify(1,p-1,p-1);
        else t.modify(1,p-1,0);
        if(p<n&&a[p+1]<a[p])t.modify(1,p,p);
        else t.modify(1,p,0);

        int ans=t.tr[1].val;
        if(ans==0)cout<<n<<endl;
        else cout<<cnt[ans]<<endl;
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    forr(i,1,N-3){
        for(int j=1;i*j<=N-3;j++)cnt[i*j]++;
    }
    int _=1;
    cin>>_;
    while (_--)
    {
        solve();
    }
    
    return 0;
}

B dp计情况数 三位前缀和优化

cpp 复制代码
const int N=304,mod=1e9+7;
//a b c数量有制约关系 可以优化一维c
int nd[N],dp[N][N][N][4];//dp[i][j][k][p] i位置 用j个a k个b 有多少情况
int sum[N][N][N];
void solve(){
    int n,q;cin>>n>>q;
    string s;
    cin>>s;s=' '+s;
    forr(i,1,n){
        nd[i]=nd[i-1]+(s[i]=='?');//nd记录i位置之前需要多少
    }
    if(s[1]=='?')dp[1][1][0][0]=dp[1][0][1][1]=dp[1][0][0][2]=1;
    else dp[1][0][0][s[1]-'a']=1;
    
    //dp计算情况数
    forr(i,2,n){
        forr(a,0,nd[i]){
            for(int b=0;b+a<=nd[i];b++){
                int c=nd[i]-a-b;
                forr(p,0,2){
                    if(s[i]=='?'){
                        if(a&&p!=0)(dp[i][a][b][0]+=dp[i-1][a-1][b][p])%=mod;
                        if(b&&p!=1)(dp[i][a][b][1]+=dp[i-1][a][b-1][p])%=mod;
                        if(c&&p!=2)(dp[i][a][b][2]+=dp[i-1][a][b][p])%=mod;

                    }else{
                        if(p==s[i]-'a')continue;
                        (dp[i][a][b][s[i]-'a']+=dp[i-1][a][b][p])%=mod;
                    }
                }
            }
        }
    }
    //sum求三维前缀和 对之后a b c的询问优化
    forr(a,0,300){
        forr(b,0,300){
            forr(c,max(nd[n]-a-b,0ll),300){
                if(a+b+c<=nd[n])(sum[a][b][c]+=((dp[n][a][b][0]+dp[n][a][b][1])%mod+dp[n][a][b][2]))%=mod;
                
                if(a)(sum[a][b][c]+=sum[a-1][b][c])%=mod;
                if(b)(sum[a][b][c]+=sum[a][b-1][c])%=mod;
                if(c)(sum[a][b][c]+=sum[a][b][c-1])%=mod;

                if(b&&c)(sum[a][b][c]+=mod-sum[a][b-1][c-1])%=mod;
                if(a&&c)(sum[a][b][c]+=mod-sum[a-1][b][c-1])%=mod;
                if(a&&b)(sum[a][b][c]+=mod-sum[a-1][b-1][c])%=mod;

                if(a&&b&&c)(sum[a][b][c]+=sum[a-1][b-1][c-1])%=mod;
            }
        }
    }
    /*
    三维前缀和
    S(x, y, z) = a(x, y, z)
                + S(x, y, z-1) + S(x, y-1, z) + S(x-1, y, z)
                - S(x, y-1, z-1) - S(x-1, y, z-1) - S(x-1, y-1, z)
                + S(x-1, y-1, z-1)
    */
    forr(i,1,q){
        int a,b,c;cin>>a>>b>>c;
        cout<<sum[a][b][c]<<endl;
    }
}
相关推荐
仟千意3 小时前
数据结构:栈和队列
数据结构
渡我白衣3 小时前
list 与 forward_list:一场 STL 中的“链表哲学”之争
数据结构·c++·list
2401_841495644 小时前
【计算机视觉】基于数学形态学的保留边缘图像去噪
人工智能·python·算法·计算机视觉·图像去噪·数学形态学·边缘保留
十八岁讨厌编程5 小时前
【算法训练营Day30】动态规划part6
算法·动态规划
CoderYanger5 小时前
优选算法-双指针:2.复写零
java·后端·算法·leetcode·职场和发展
charlie1145141916 小时前
理解C++20的革命特性——协程支持2:编写简单的协程调度器
c++·学习·算法·设计模式·c++20·协程·调度器
hadage2336 小时前
--- 常见排序算法汇总 ---
算法·排序算法
Mrs.Gril6 小时前
目标检测:yolov7算法在RK3588上部署
算法·yolo·目标检测
WWZZ20257 小时前
ORB_SLAM2原理及代码解析:单应矩阵H、基础矩阵F求解
线性代数·算法·计算机视觉·机器人·slam·基础矩阵·单应矩阵