• 2019 ICPC银川 个人题解



    title : 2019 ICPC银川 个人题解
    date : 2022-11-21
    tags : ACM,题解,练习记录
    author : Linno


    2019 ICPC银川 个人题解

    题目链接:https://codeforces.com/gym/104021

    补题进度:6/12

    B-So Easy

    对于行和列分别减一次最小值,那么隐藏的那个格子的值就可以由上下左右推导出来。

    #include
    #define int long long 
    using namespace std;
    const int N=1005;
    
    int n,mp[N][N];
    
    signed main(){
    	ios::sync_with_stdio(0);
    	cin.tie(0);cout.tie(0);
    	cin>>n;
    	int sx=1,sy=1;
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=n;++j){
    			cin>>mp[i][j];
    			if(mp[i][j]==-1){
    				sx=i;sy=j;
    				mp[i][j]=0;
    			}
    		}
    	}
    	for(int i=1;i<=n;++i){
    		int mi=1e9; 
    		if(i==sx) continue; 
    		for(int j=1;j<=n;++j) mi=min(mi,mp[i][j]);
    		for(int j=1;j<=n;++j) mp[i][j]-=mi;
    	}
    	for(int j=1;j<=n;++j){
    		int mi=1e9; 
    		if(j==sy) continue;
    		for(int i=1;i<=n;++i) if(sx!=i||sy!=j) mi=min(mi,mp[i][j]);
    		for(int i=1;i<=n;++i) mp[i][j]-=mi;
    	}
    	int ans=max(mp[sx-1][sy],mp[sx+1][sy])+max(mp[sx][sy+1],mp[sx][sy-1]);
    	cout<<ans<<"\n";
    	return 0;
    }
    /*
    3
    5 -1 11
    6 10 12
    7 11 13
    
    2
    1 4
    2 -1
    
    3
    -1 4 4
    5 5 5
    8 8 8
    
    3
    4 6 8
    4 6 8
    -1 6 8
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    F-Function!

    式子里边一个log是恒为1的,另一个log在a大于根号的时候也是恒为1,两边分别分块处理即可。第二个部分可以推得 a n s = ∑ i = n + 1 n i ∗ ( n − i + 1 ) ans=\sum_{i=\sqrt n+1}^n i*(n-i+1) ans=i=n +1ni(ni+1),这里做个前缀和就只需要求 ∑ i = 1 x i ∗ ( n − i + 1 ) \sum_{i=1}^x i*(n-i+1) i=1xi(ni+1)即可,把括号去掉就是我们熟悉的求和公式了。

    #include
    #define int __int128
    //#define int long long
    using namespace std;
    const int mod=998244353;
    int n,inv2,inv6;
    
    int read(){	int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
    void write(int x){if(x>9) write(x/10);putchar(x%10+'0');}
    
    inline int fpow(int a,int b){
    	int res=1;
    	while(b){
    		if(b&1) res=res*a%mod;
    		a=a*a%mod;
    		b>>=1; 
    	}
    	return res;
    }
    
    int inv(int x){
    	return fpow(x,mod-2);
    }
    
    inline int pre(int x){
    	int res=(n+1)%mod*x%mod*(x+1)%mod*inv2%mod;
    	res-=x*(x+1)%mod*(2ll*x+1)%mod*inv6%mod;
    	return (res+mod)%mod;
    }
    
    signed main(){
    	n=read();
    	inv2=inv(2);inv6=inv(6);
    	int ans=0;
    	for(int a=2;a*a<=n;++a){
    		int res=0;
    		for(int b=a,i=1;b<=n;b*=a,++i){
    			int r=min(n,b*a-1);
    			res+=(r-b+1)*i%mod;
    			res%=mod;
    		}
    		ans+=res*a%mod;ans%=mod;
    	}
    	ans=(ans+pre(n)-pre(sqrtl(n))+mod)%mod;
    	write(ans);putchar('\n');
    	return 0;
    }
    /*
    1000000000000
    */ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    G-Pot!!

    裸的线段树,乘的数直接以因子个数的形式记下来,那么建4棵线段树就能搞定了。

    #include
    #define int long long
    using namespace std;
    const int N=1e5+7,M=(N<<5);
    
    int n,m;
    #define ls (p<<1)
    #define rs (p<<1|1)
    #define mid ((l+r)>>1)
    int tr[N<<2][5],tg[N<<2][5];
    
    void pushdown(int p,int i){
    	if(tg[p][i]){
    		tr[ls][i]+=tg[p][i];
    		tr[rs][i]+=tg[p][i];
    		tg[ls][i]+=tg[p][i];
    		tg[rs][i]+=tg[p][i];
    		tg[p][i]=0;
    	}
    }
    
    inline void modify(int p,int l,int r,int ql,int qr,int pri,int val){
    	if(ql<=l&&r<=qr){
    		tr[p][pri]+=val;
    		tg[p][pri]+=val;
    		return;
    	}
    	pushdown(p,pri);
    	if(ql<=mid) modify(ls,l,mid,ql,qr,pri,val);
    	if(qr>mid) modify(rs,mid+1,r,ql,qr,pri,val);
    	tr[p][pri]=max(tr[ls][pri],tr[rs][pri]);
    }
    
    inline int query(int p,int l,int r,int ql,int qr,int pri){
    	if(ql<=l&&r<=qr) return tr[p][pri];
    	pushdown(p,pri);
    	int res=0;
    	if(ql<=mid) res=query(ls,l,mid,ql,qr,pri);
    	if(qr>mid) res=max(res,query(rs,mid+1,r,ql,qr,pri));
    	return res; 
    }
    
    signed main(){
    	cin>>n>>m;
    	string op;
    	for(int i=1,l,r,x;i<=m;++i){
    		cin>>op>>l>>r;
    		if(op=="MULTIPLY"){
    			cin>>x;
    			while(x%2==0) x/=2,modify(1,1,n,l,r,1,1); 
    			while(x%3==0) x/=3,modify(1,1,n,l,r,2,1);
    			while(x%5==0) x/=5,modify(1,1,n,l,r,3,1);  
    			while(x%7==0) x/=7,modify(1,1,n,l,r,4,1);
    		}else{
    			int mx=0;
    			for(int i=1;i<=4;++i) mx=max(mx,query(1,1,n,l,r,i));
    			cout<<"ANSWER "<<mx<<"\n";
    		}
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    I-Base62

    虽然很签到,但是用python还是有很多不方便的地方。

    def change(x):
        if(x>=48 and x<=57):
            return x-48
        elif(x>=65 and x<=90):
            return x-65+10
        elif(x>=97 and x<=122):
            return x-97+36
    
    def backto(x):
        if(x<10):
            return x
        elif x<36:
            return chr(x-10+65)
        else:
            return chr(x-36+97)
    
    X,Y,Z=input().split()
    X=int(X)
    Y=int(Y)
    num=0
    for i in Z[::]:
        num=num*X+change(ord(i))
    
    ans=[]
    flag=0
    while(num):
        ans.append(num%Y)
        num=num//Y
        flag=1
    if flag :
        ans=ans[::-1]
        for i in ans[::]:
            print(backto(i),end='')
    else :
        print('0')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    K-Largest Common Submatrix

    因为是排列,我们可以对每个位置直接求向左能延申多少,然后分别再求以这个作为最短边,向上和向下分别能延申多少,然后就可以直接统计答案了。

    #include
    #define int long long
    #define mk make_pair
    #define pii pair<int,int>
    #define F first
    #define S second 
    using namespace std;
    const int N=2007;
    
    int n,m,A[N][N],B[N][N],mx[N][N],L[N][N],R[N][N];
    pii pos[N*N]; 
    int stk[N],top=0;
    
    bool check(int x1,int y1,int x2,int y2){
    	if(pos[B[x1][y1]].F-x1==pos[B[x2][y2]].F-x2&&pos[B[x1][y1]].S-y1==pos[B[x2][y2]].S-y2) return true;
    	return false;
    }
    
    signed main(){
    	ios::sync_with_stdio(0);
    	cin.tie(0);cout.tie(0);
    	cin>>n>>m;
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			cin>>A[i][j];
    			pos[A[i][j]].F=i;
    			pos[A[i][j]].S=j;
    		}
    	}
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			cin>>B[i][j];
    		}
    	}
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			mx[i][j]=0;
    			L[i][j]=R[i][j]=i; //能够向上和向下延申多少 
    			int a=pos[B[i][j]].F,b=pos[B[i][j]].S;
    			while(b+mx[i][j]<=m&&j+mx[i][j]<=m&&A[a][b+mx[i][j]]==B[i][j+mx[i][j]]) ++mx[i][j];
    		}
    	}
    	for(int j=1;j<=m;++j){
    		for(int i=2;i<=n;++i){
    			if(mx[i-1][j]>=mx[i][j]&&check(i,j,i-1,j)) L[i][j]=L[i-1][j];
    			while(L[i][j]-1>=1&&mx[i][j]<=mx[L[i][j]-1][j]){
    				if(!check(i,j,L[i][j]-1,j)) break;
    				--L[i][j];
    			}
    		}
    		for(int i=n-1;i>=1;--i){
    			if(mx[i+1][j]>=mx[i][j]&&check(i,j,i+1,j)) R[i][j]=R[i+1][j];
    			while(R[i][j]+1<=n&&mx[i][j]<=mx[R[i][j]+1][j]){
    				if(!check(i,j,R[i][j]+1,j)) break;
    				++R[i][j]; 
    			}
    		}
    	}
    	int ans=0;
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			ans=max(ans,mx[i][j]*(R[i][j]-L[i][j]+1));
    		//	if(mx[i][j]*(R[i][j]-L[i][j]+1)==3) cout<
    		}
    	}
    	cout<<ans<<"\n";
    	return 0;
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    N-Fibonacci Sequence

    #include
    using namespace std;
    
    signed main(){
    	cout<<"1 1 2 3 5\n";
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    【问题思考总结】已知对角矩阵怎么求原矩阵?原矩阵唯一吗?【相似对角化】
    Solidity 小白教程:18. Import
    12 Synchronized与锁升级
    TCP的发送系列 — 发送缓存的管理(一)
    【内网渗透】vulnhub三个基础靶场wp
    使用axis调用WebService,Java WebService调用工具类
    FFmpeg入门 - rtmp推流
    操作文档的用户故事怎么写,敏捷开发
    前端的强缓存和协商缓存
    JavaScript 知识梳理基础篇(一)
  • 原文地址:https://blog.csdn.net/SC_Linno/article/details/127957108