zoukankan      html  css  js  c++  java
  • JZOJPJ-C 8/21题解

    原题大战D1

    吐槽:

    1. T1 (O(N^2); N leq 26) N大时还要写高精, 可以增加难度

    2. T2 不给范围

    3. T3 居然没有完全卡掉 不对应该赞美出题人

    4. T4 PJ考个四边形不等式?? orz 出题人 %%%

    这里是点名被卡的直接高精选手.

    并没有感觉很卡啊, 写了就过了啊

    因为平常高精求余是这么写的

    pair<string, string> divide(string a, string b){
    	for(int i=0;i<a.size()-b.size();++i)
    		ans+=divide(a, i, i+b.size(), b) ; // 顺带求出余数
    }
    

    但是我的高精是这样的:

    string mod(string x, string y){
    	string ans ; 
    	for(int i=0;i<x.size();++i) {
    		ans=ans+x[i] ; 
    		while(!cmp(ans,y)) minu(ans, y) ;
    	}
    	return ans ;
    }
    

    这种写法的优点在于:

    1. 码量小(高精除了除码量都不大)

    2. 常数小, 具体来说, 采用第一种写法执行了10次乘法(高精乘单精)以求出除得的值(但其实用二分只用至多4次, 而且不断加也可以), 而这里执行的是减法, 不需要取余,所以常数较小. 并且该算法较玄学, 卡不满? 并且开上O2, O3后, STL常数极小

    3. 能AC本题

    gcd主要代码如下:

    string gcd(string x, string y){
    	if(y == 1) return 1; // 加速
    	if(y == "0" || y.empty()) return x;
    	return gcd(y, mod(x, y)) ;
    }
    

    可以看见特判了1, 这是因为y=1要执行10*len(x)次高精减法及判断

    并且可以发现, 在y变大时, 执行减法次数逐渐缩小, 而很小时取膜可以让较大的数减少一个很大的值(说了这么多就是玄学算法过了2333)

    T1

    题意

    给出一颗二叉树的前序遍历和后序遍历,求有多少种这样的二叉树

    解法

    考虑递归的求解, 一个节点的子树是他在前序遍历中的位置到他在后序遍历中的位置

    那么如果一个节点只有一颗子树, 挂在左边/右边并不会影响遍历, 即方案数乘2

    知识点

    递归

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    using namespace std ;
    #define int long long
    int power(int a,int b){ int res=1, car=a ; while(b){ if(b&1) res*=car ; car*=car ; b>>=1 ; } return res; }
    string p, q; int len ; int cnt;
    void calc(int a1,int b1,int a2,int b2){ int i; if(a1>=b1) return; for(i=a2;i<=b2-1;++i) if(p[a1+1] == q[i])  break; if(i==b2-1) ++cnt; calc(a1+1,a1+1+(i-a2),a2,i); calc(a1+1+(i-a2)+1,b1,i+1,b2-1);}
    signed main(){ freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); cin>>p>>q ; len = p.size() ; calc(0,len-1,0,len-1); printf("%lld
    ", power(2, cnt));}
    

    T2

    题意

    定义一个八连通的联通块的块大小为其权值, 求所有的权值中

    1. 最大的是多少

    2. 大于等于一个给定k的有多少个

    解法

    无脑暴力BFS即可

    O(NM)

    错误

    在判断能否走向一个方向时, 写错函数名(复制时忘记修改)导致考场爆0

    现已修改

    知识点

    BFS

    代码

    #pragma optimize(2)
    #pragma optimize(3)
    
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #define pir pair<int, int>
    using namespace std ;
    int mp[1005][1005]; int n,m,k ; queue< pir > q; int vis[1005][1005] ;
    int chk(pir x) {return mp[x.first][x.second]=='.'; } 
    pir up(pir x){ return make_pair(x.first-1, x.second) ; } 
    pir dn(pir x){ return make_pair(x.first+1, x.second) ; } 
    pir le(pir x){ return make_pair(x.first, x.second+1) ; } 
    pir ri(pir x){ return make_pair(x.first, x.second-1) ; } 
    pir ul(pir x){ return make_pair(x.first+1, x.second-1) ; } 
    pir ur(pir x){ return make_pair(x.first+1, x.second+1) ; } 
    pir dl(pir x){ return make_pair(x.first-1, x.second-1) ; } 
    pir dr(pir x){ return make_pair(x.first-1, x.second+1) ; }
    #define put(X) cout<<"At "<<k.first<<" "<<k.second<<endl
    int bfs(int sx, int sy, int num){
    	q.push(make_pair(sx, sy)); 
    	vis[sx][sy]=num; int wyxkk=0 ; 
    	while(!q.empty()){ 
    		pir k = q.front(); q.pop(); ++wyxkk ; 
    		//cout<<"At "<<k.first<<" "<<k.second<<endl ;
    		if((!vis[up(k).first][up(k).second]) && chk(up(k))) vis[up(k).first][up(k).second]=num, q.push(up(k)); 
    		if((!vis[dn(k).first][dn(k).second]) && chk(dn(k))) vis[dn(k).first][dn(k).second]=num, q.push(dn(k)); 
    		if((!vis[le(k).first][le(k).second]) && chk(le(k))) vis[le(k).first][le(k).second]=num, q.push(le(k)); 
    		if((!vis[ri(k).first][ri(k).second]) && chk(ri(k))) vis[ri(k).first][ri(k).second]=num, q.push(ri(k)); 
    		if((!vis[ul(k).first][ul(k).second]) && chk(ul(k))) vis[ul(k).first][ul(k).second]=num, q.push(ul(k)); 
    		if((!vis[ur(k).first][ur(k).second]) && chk(ur(k))) vis[ur(k).first][ur(k).second]=num, q.push(ur(k)); 
    		if((!vis[dl(k).first][dl(k).second]) && chk(dl(k))) vis[dl(k).first][dl(k).second]=num, q.push(dl(k)); 
    		if((!vis[dr(k).first][dr(k).second]) && chk(dr(k))) vis[dr(k).first][dr(k).second]=num, q.push(dr(k));
    	} 
    	return wyxkk ; 
    }
    int ans=-0x3f3f3f3f, pans=0 ;
    int main(){	
    	freopen("storm.in", "r" , stdin); freopen("storm.out", "w", stdout);
    	scanf("%d%d", &n, &m) ; 
    	for(int i=1;i<=n;++i){ 
    		string p; cin>>p; 
    		for(int j=1;j<=m;++j) mp[i][j]=p[j-1]; 
    	}
    	scanf("%d", &k); 
    	for(int i=1;i<=n;++i)  
    		for(int j=1;j<=m;++j)  
    			if(!vis[i][j] && chk(make_pair(i, j))) {
    				int pm = bfs(i, j, 1) ;
    				//cout<<pm<<endl;
    				ans=max(ans, pm); if(pm >= k) ++pans ; 
    			} 
    	cout<<pans<<" "<<ans<<endl ; 
    }
    

    T3

    题意

    求两个大数的gcd

    解法

    暴力gcd, 套个高精度即可

    知识点

    高精度, gcd

    代码

    #pragma optimize(2)
    #pragma optimize(3)
    
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    using namespace std ;
    int cmp(string str1,string str2){ if(str1.size()!=str2.size()) return str1.size() < str2.size() ; else for(int i=0; i<str2.size(); ++i) if(str1[i] != str2[i]) return str1[i] < str2[i] ; return 0 ;}
    string minu(string str1, string str2){ if(!cmp(str1, str2) && !cmp(str2, str1)) return "" ; int Q = str1.size()-str2.size() ; for(int i=str2.size()-1; i>=0; --i) str1[i+Q]-=(str2[i]-'0') ; for(int i=str1.size()-1; i>0; --i) if(str1[i] < '0') str1[i]+=10, --str1[i-1] ; str1.erase(0,str1.find_first_not_of('0'));return str1 ; }
    string mod(string str1,string str2){ string ans ; ans.clear() ; for(int i=0; i<str1.size(); ++i) { ans = ans+str1[i] ; while(!cmp(ans, str2)) ans=minu(ans, str2); } return ans ; }
    string gcd(string x, string y){ if(x.empty() || x=="0") return y ; return gcd(mod(y,x), x) ; }
    int main(){ freopen("gcd.in", "r" , stdin); freopen("gcd.out", "w", stdout); string p,q; cin>>p>>q; if(p=="1" || q=="1") return puts("1"),0; cout<<gcd(p, q)<<endl; }
    

    T4

    题意

    石子合并

    解法

    原题……

    众所周知石子合并满足四边形不等式, 打个(我从没打过)的四边形不等式即可

    代码奇短?

    知识点

    四边形不等式, DP

    代码

    #pragma optimize(2)
    #pragma optimize(3)
    
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    using namespace std ;
    int a[4005], sum[4005]; int dp[4005][4005], P[4005][4005], ans=0x3f3f3f3f, n;
    int main(){
        freopen("stone.in", "r", stdin); freopen("stone.out", "w", stdout) ; scanf("%d",&n);
        for(int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i+n]=a[i]; sum[i]=sum[i-1]+a[i]; P[i][i]=i; } for(int i=1+n;i<=(n<<1);i++){ sum[i]=sum[i-1]+a[i]; P[i][i]=i; }
        for(int i=(n<<1)-1;i;i--)
            for(int j=i+1,pos=0,tmp=0x3f3f3f3f;j<=(n<<1);j++,pos=0,tmp=0x3f3f3f3f)
                for(int k=P[i][j-1];k<=P[i+1][j];k++) if(dp[i][k]+dp[k+1][j]+(sum[j]-sum[i-1])<tmp) tmp=dp[i][k]+dp[k+1][j]+(sum[j]-sum[i-1]), pos=k, P[i][j]=pos, dp[i][j]=tmp;
        for(int i=1;i<=n;i++) ans=min(ans,dp[i][i+n-1]); printf("%d
    ",ans);
    }
    
  • 相关阅读:
    加法原理和乘法原理
    布尔矩阵
    Codeforces Round #603 (Div. 2) A. Sweet Problem
    Codeforces Round #603 (Div. 2) D. Secret Passwords 并查集
    poj1611The Suspects并查集
    poj 2236 Wireless Network 并查集
    求斐波那契数的python语言实现---递归和迭代
    python语言实现阶乘的两种方法---递归和迭代
    栈实现二进制转十进制
    栈的基本操作
  • 原文地址:https://www.cnblogs.com/tyqtyq/p/11387512.html
Copyright © 2011-2022 走看看