CF Manthan, Codefest 19 (open for everyone, rated, Div. 1 + Div. 2) (C D E F 문제 풀이)
제목 링크
(경기 때 A, B 를 풀 고 C 를 보다 가 중간 에 포기 하고 싶 었 는데 갑자기 낙서 를 한 번 하고 넘 어가 서 D 를 써 보 니 생각 이 났 지만 시간 이 3 문제 로 끝나 지 않 았 다. B 문제 FST 를 생각 하지 못 했다)
C 매 직 그리드 (마구 잡 이)
제목:
n * 8727 ° n * n * n * 8727 ° n 의 행렬 을 구성 해 야 합 니 다. n n n 은 444 의 배수 로 모든 줄, 각 열의 차이 나 합 이 같 습 니 다.
생각:
바로 샘플 의 4 * 8727 ° 4 * 4 * 8727 ° 4 행렬 을 하나의 단원 으로 삼 아 행렬 을 계속 채 우 는 것 이다. 매번 원 행렬 단원 에 16, 32, 48... 16, 32, 48... 16, 32, 48 을 더 하면 된다.
코드:
#include
using namespace std;
const int N=2000;
int n;
int arr[N][N];
int cl(int x,int y){
return (x/4)*(n/4)+(y/4);
}
int a[4][4]={
{8,9,1,13},
{3,12,7,5},
{0,2,4,11},
{6,10,15,14}
};
int main()
{
cin>>n;
for(int i=0;i
D Restore Permutation (선분 트 리)
제목:
하나의 배열 d [i] d [i] d [i] 를 지정 하고 1 - n 1 - n 1 - n 의 배열 S S S S 를 구성 하여 모든 i i 에 대해 d [i] = > j S [j] (1 < = j < i & S [j] < S [i]) d [i] = \ sum{j}{S[j](1<=j생각:
처음에는 나무 모양 의 배열 을 사용 하려 고 했 지만 생각 이 뚜렷 하지 않 았 다. 나중에 동료 들 은 선분 나무 로 한다 고 말 했다. 순환 적 으로 1 - n 1 - n 1 - n 을 찾 았 고 디지털 i i 에 대해 d [i] d [i] d [i] 배열 에서 가장 오른쪽 에 있 는 0 의 위치 p i p 를 찾 았 다.i pi, 그럼 S p i S{p i} Spi 는 i i 를 위 한 것 이 며, d [i] d [i] d [i] 중의 [p i - n] [p - i - n] [pi - n] 을 i i i 를 빼 면 된다.
코드:
#include
#define ls x<<1 #define rs x<<1|1 #define ll long long using namespace std; const int N=2e5+10; ll arr[N]; int n; struct node{ int l,r; ll sum,mi,f,siz;// , 0 , sum }e[N*4]; void up(int x){ e[x].mi=min(e[ls].mi,e[rs].mi); e[x].sum=e[ls].sum+e[rs].sum; } void down(int x){ if(e[x].f==0)return ; ll f=e[x].f; e[ls].f+=f;e[rs].f+=f; e[ls].mi+=f;e[rs].mi+=f; e[ls].sum+=e[ls].siz*f;e[rs].sum+=e[rs].siz*f; e[x].f=0; } void built(int x,int l,int r){ e[x].l=l;e[x].r=r;e[x].siz=(r-l+1);e[x].f=0; if(l==r){ e[x].mi=e[x].sum=arr[l]; return ; } int mid=(l+r)/2; built(ls,l,mid);built(rs,mid+1,r); up(x); } void adds(int x,int pos,ll v){// , , if(e[x].l==e[x].r){ e[x].mi=e[x].sum=v; return ; } down(x); int mid=(e[x].l+e[x].r)/2; if(pos<=mid)adds(ls,pos,v); else adds(rs,pos,v); up(x); } void addr(int x,int LL,int RR,ll v){// if(LL>RR)return ; if(e[x].l>=LL&&e[x].r<=RR){ e[x].sum+=e[x].siz*v;e[x].mi+=v; e[x].f+=v; return ; } down(x); int mid=(e[x].l+e[x].r)/2; if(LL<=mid)addr(ls,LL,RR,v); if(RR>mid)addr(rs,LL,RR,v); up(x); } int query(int x){ if(e[x].l==e[x].r)return e[x].l; down(x); if(e[rs].mi==0)return query(rs); return query(ls); } int debug(int x,int pos){ if(e[x].l==e[x].r)return e[x].mi; down(x); int mid=(e[x].l+e[x].r)/2; if(pos<=mid)return debug(ls,pos); else return debug(rs,pos); } int t[N]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%lld",&arr[i]); built(1,1,n); for(int i=1;i<=n;i++){ int p=query(1);//cout<
E Let Them Slide (ST表 + 差分)
题意:
给定一个 n ∗ m n*m n∗m 的矩阵,每一行有一个长度为 l e n i len_i leni 的数组 a i a_i ai ,可以左右移动,问通过数组的移动可以使得每一列的数字之和是多少(每一列单独计算),可以移出矩阵,此时贡献为 0 0 0 。 ( − 1 e 9 < = a i < = 1 e 9 ) (-1e9<=a_i<=1e9) (−1e9<=ai<=1e9)
思路:
首先在纸上模拟一个数组在矩阵中左右移动,可以发现对于矩阵的某一列 j j j ,对于第 i i i 个数组中可以移动到 j j j 列的范围 [ L , R ] [L,R] [L,R] 是确定的,那么这个数组对这一列的贡献就是 m a x ( a [ i ] , L < = i < = R ) max(a[i],L<=i<=R) max(a[i],L<=i<=R) ,但是如果对于每一个数组都扫一遍要 n ∗ m n*m n∗m 的复杂度必然超时,注意到 ∑ ( l e n i ) < = 1 e 6 \sum(len_i)<=1e6 ∑(leni)<=1e6 。那我们对于 l e n i ∗ 2 > = m len_i*2>=m leni∗2>=m 的数组,可以直接扫一遍,但是对于 l e n i ∗ 2 < m len_i*2<m leni∗2<m 的情况,我们其实可以在纸上发现规律,从前往后,对于第 j ( j < = l e n i ) j\ (j<=len_i) j (j<=leni) 列,能产生贡献的必然是 [ 1 , j ] [1,j] [1,j] 从后往前也是类似,对于中间的部分发现他们的贡献区间都相同故使用差分数组维护区间加即可避免遍历所有列。
代码:
#include
#define ll long long
using namespace std;
const int N=2e6+10;
int n,m;
int st[N][21];
ll ans[N];
void cl(int x){// ST
for(int i=1;i<=20;i++)
for(int j=1;j<=x;j++)st[j][i]=max(st[j][i-1],st[j+(1<=m){//
for(int j=1;j<=m;j++){
int l=len-m+j,r=j;int v=mi(max(l,1),min(len,r));//
if(l<1||r>len)v=max(v,0);//
ans[j]+=v;//
ans[j+1]-=v;
}
}else{
int v1=0,v2=0;
for(int j=1;j<=len;j++){
v1=max(v1,st[j][0]);// k
v2=max(v2,st[len-j+1][0]);// k
ans[j]+=v1;ans[j+1]-=v1;
ans[m-j+1]+=v2;ans[m-j+2]-=v2;
}
ans[len+1]+=v1;//
ans[m-len+1]-=v1;
}
}
for(int i=1;i<=m;i++){
ans[i]+=ans[i-1];//
printf("%lld ",ans[i]);
}
puts("");
}
F (비트 연산 + 욕심)
제목:
배열 지정, m a x 요구 ( a i ∣ ( a j & a k ) ) ( i < j < k ) max\ (a_i\ |\ (a_j \&a_k)\ )\ (\ i
뒤에서 앞으로 모든 a i a i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i- a n ai + 1 - an 이 가 질 수 있 는 11 - 1 의 집합 은 한 위치 에서 11 - 1 이 두 번 나타 나 면 우 리 는 이 두 수 를 a j, a k a j, a k aj, ak 로 삼 아 a - a i ai 라 는 사람 을 1 로 계속 답 을 업데이트 하면 된다.
코드:
#include
using namespace std;
const int N=(1<<21);
int cnt[N],vis[N];
int n;
int a[N];
void ins(int x,int time){// ,time
if(cnt[x]==2||vis[x]==time)return ;
cnt[x]++;vis[x]=time;
for(int i=20;i>=0;i--){
if((x>>i)&1){
ins(x^(1<=1;i--){//
int s=0;
for(int j=20;j>=0;j--){//
if(((a[i]>>j)&1)==0){
if(cnt[s|(1<
by YaoYaoLe
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Codeforces 1287C Garland제목 링크:Codeforces 1287C Garland 사고방식: 우리기dp[i][j][0]와 dp[i][j][1]는 각각 i개가 홀수/짝수이고 앞의 i개 안에 j개의 짝수가 있는 상황에서 i개의 최소 복잡도.첫 번...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.