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∗(n−i+1),这里做个前缀和就只需要求 ∑ i = 1 x i ∗ ( n − i + 1 ) \sum_{i=1}^x i*(n-i+1) ∑i=1xi∗(n−i+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;
}