2019 ICPC银川 个人题解

57 篇文章 0 订阅
38 篇文章 0 订阅

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


2019 ICPC银川 个人题解

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

补题进度:6/12

B-So Easy

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

#include<bits/stdc++.h>
#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
*/

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<bits/stdc++.h>
#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
*/ 

G-Pot!!

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

#include<bits/stdc++.h>
#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;
}

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')

K-Largest Common Submatrix

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

#include<bits/stdc++.h>
#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<<i<<" "<<j<<"!!\n"; 
		}
	}
	cout<<ans<<"\n";
	return 0;
} 

N-Fibonacci Sequence

#include<bits/stdc++.h>
using namespace std;

signed main(){
	cout<<"1 1 2 3 5\n";
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RWLinno

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值