[경기 매듭과 문제풀이] Codeforces Global Round 1 욕심 주의, 간단한 dp 기교, 그리고 AC 자동기 + 디지털 dp

중요한 문제부터 문제풀이 연결
1110H - Modest Substrings
제목: 길이가 n인 문자열을 구하고 최대 몇 개의 하위 문자열 x를 구하며 L<=x<=R, |L|<=|R|<=800, n<=2000을 만족시키면 모두 10진법 표시입니다
이것은 디지털 dp의 좋은 문제다!fdf 양반의 가르침에 감사 드립니다.fdf의 문제풀이는 모든 하위 문자열의 공헌을 처음으로 제한에서 벗어난 곳에 놓고 통계합니다.제한을 벗어나면 l 또는 r의 접두사를 열거하고 다음 차원 통계를 열거할 수 있다.여기서 우리는 이 열의 길이를 고정시켜야 한다. 제한을 벗어난 후에 임의로 채워야 하기 때문에 길이가 합법적이면 [l]<|r|-1이면 둘 사이의 열을 통계해야 한다.제한에서 벗어난 모든 열을 AC 자동기에 삽입(모든 상태의 제한에서 벗어난 합법적인 길이를 기록)하면 이 노드와 일치하고 길이가 합법적이면 답안을 공헌할 수 있다.또한 모든 페일 나무의 조상들은 이 상태의 접미사로 답을 바칠 수 있다.f(i, u)는 길이가 i임을 나타내며 AC 로봇에서 u와 일치하는 가장 좋은 답안을 나타낸다.이동할 때 g(x, i)를 미리 처리하면 노드 x를 표시하고 길이 i가 공헌할 수 있는 답안수를 남깁니다.사전의 순서가 가장 작아야 하기 때문에 기억화 검색을 하고 위치별로 가장 좋은 코드를 확정하여 분류하는 토론을 매우 길게 썼지만 주석은 비교적 뚜렷하다
총결산: L=R의 특판이 잘못 걸려서 1시간을 조정했다.이런 오류는 정말 모든 코드의 세부 사항을 꼼꼼히 보아야 한다. 대조를 빌려서는 안 된다!왜 아직도 카메라에 오류가 나면 어디가 틀렸는지 알 수 있지만 코드를 보면 알아낼 수가 없어요.반드시 자신의 문제를 조정하는 악습을 고쳐야 하며, 반드시 마음을 가라앉히고 곳곳의 잘못을 알아내야 한다!코드는 정말 한 마디 한 마디 읽어야 해!뼈에 사무치는 교훈이여!
#include
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) (x&(-x))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,char> pr;

const ll inf = 2e18;
const int N = 2e4 + 10;
const int maxn = 2020;
const ll mod = 1e9 + 7;

char s1[maxn],s2[maxn];
int a[maxn],b[maxn];
int lenl,lenr,n;
int f[maxn][N],nxt[N][10],fail[N],g[N][maxn],trans[N][10],tot;

void init(){
	int cur = 0;
	rep(i,1,lenl) a[i] = s1[i] - '0';
	rep(i,1,lenr) b[i] = s2[i] - '0';
	if ( lenl < lenr ){ // 、          
		cur = 0;
		rep(i,1,lenl){
			rep(j,a[i] + 1,9){ //         。        。                  、           
				if ( !nxt[cur][j] ) nxt[cur][j] = ++tot;
				int x = nxt[cur][j];
				g[x][lenl - i]++;
			}
			if ( !nxt[cur][a[i]] ) nxt[cur][a[i]] = ++tot;
			cur = nxt[cur][a[i]];
		}	
		g[cur][0]++;//         
		
		cur = 0;
		rep(i,1,lenr){
			rep(j,0,b[i] - 1){
				if ( i == 1 && !j ) continue; //         0
				if ( !nxt[cur][j] ) nxt[cur][j] = ++tot;
				int x = nxt[cur][j];
				g[x][lenr - i]++;
	
			}
			if ( !nxt[cur][b[i]] ) nxt[cur][b[i]] = ++tot;
			cur = nxt[cur][b[i]];
		}	
		g[cur][0]++;

		if ( lenr > lenl + 1 ){ //            0  
			cur = 0;
			rep(i,1,9){
				int &x = nxt[cur][i];
				if ( !x ) x = ++tot;
				rep(j,lenl + 1,lenr - 1) g[x][j - 1]++; //j - 1      
			}
		}
	}
	else{ //       ,       
		int id = lenl + 1;
		rep(i,1,lenl){
			if ( a[i] != b[i] ){
				rep(j,a[i] + 1,b[i] - 1){ //              
					if ( !nxt[cur][j] ) nxt[cur][j] = ++tot;
					int x = nxt[cur][j];
					g[x][lenl - i]++;
				}
				id = i + 1;
				break;
			}
			if ( !nxt[cur][b[i]] ) nxt[cur][b[i]] = ++tot;
			cur = nxt[cur][b[i]];
		}
		if ( id > lenl ){ //          
			if ( a[lenl] == b[lenl] ){ //       ,          
			//	if ( !nxt[cur][b[lenl]] ) nxt[cur][b[lenl]] = ++tot;
			//	cur = nxt[cur][b[lenl]];
			//    cur          !
				g[cur][0]++;
			}
			else{ //         ,        ,           
				if ( !nxt[cur][b[lenl]] ) nxt[cur][b[lenl]] = ++tot;
				int x = nxt[cur][b[lenl]];
				g[x][0]++;
				if ( !nxt[cur][a[lenl]] ) nxt[cur][a[lenl]] = ++tot;
				x = nxt[cur][a[lenl]];
				g[x][0]++;
			}
		}
		else{
			int y = cur;
			if ( !nxt[cur][a[id - 1]] ) nxt[cur][a[id - 1]] = ++tot;
			cur = nxt[cur][a[id - 1]]; 
			rep(i,id,lenl){
				rep(j,a[i] + 1,9){
					if ( !nxt[cur][j] ) nxt[cur][j] = ++tot;
					int x = nxt[cur][j];
					g[x][lenl - i]++;
				}
				if ( !nxt[cur][a[i]] ) nxt[cur][a[i]] = ++tot;
				cur = nxt[cur][a[i]];
			}
			g[cur][0]++;
			cur = y;
			if ( !nxt[cur][b[id - 1]] ) nxt[cur][b[id - 1]] = ++tot;
			cur = nxt[cur][b[id - 1]];
			rep(i,id,lenr){
				rep(j,0,b[i] - 1){
					if ( !nxt[cur][j] ) nxt[cur][j] = ++tot;
					int x = nxt[cur][j];
					g[x][lenr - i]++;
				}
				if ( !nxt[cur][b[i]] ) nxt[cur][b[i]] = ++tot;
				cur	 = nxt[cur][b[i]];
			}
			g[cur][0]++;
		}
	}
}
int q[N],hh,tt;
void print_trie(){
	int x = 0;
	tt = hh = 0;
	q[tt++] = x;
	while ( hh < tt ){
		int x = q[hh++];
		cout<<x<<" : "<<endl;
		rep(i,0,9){
		
			if ( nxt[x][i] ){
				q[tt++] = nxt[x][i];
				cout<<i<<" "<<nxt[x][i]<<endl;
			}			
		}
		cout<<endl;
	}
}
void build(){
	rep(i,0,9) if ( nxt[0][i] ) q[tt++] = nxt[0][i];
	while ( hh < tt ){
		int x = q[hh++];
		rep(i,0,9){
			if ( nxt[x][i] ){
				int y = nxt[x][i] , p = fail[x];
				while ( p && !nxt[p][i] ) p = fail[p];
				fail[y] = nxt[p][i];
				q[tt++] = y;
			}
		}
	}
	rep(i,0,tt - 1){ //  fail                      ,    i,               (             
		int x = q[i] , y = fail[x]; //            
		rep(j,1,n) g[x][j] += g[x][j - 1];
		rep(j,0,n){
			g[x][j] += g[y][j];
		}
	}
//	print_trie();
	rep(x,0,tot){ //  trans    0   
		rep(j,0,9){
			int p = x;
			while ( p && !nxt[p][j] ) p = fail[p];
			trans[x][j] = nxt[p][j];
		}
	}
}
pr from[maxn][N];
bool vis[maxn][N];
int DP(int n,int m){ //      ,         。          
	if ( !n ) return 0;
	if ( vis[n][m] ) return f[n][m];
	vis[n][m] = 1; int &d = f[n][m];
	rep(i,0,9){
		int to = trans[m][i];
		int cur = DP(n - 1,to) + g[to][n - 1];
		if ( cur > d ){
		   	d = cur;
			from[n][m] = mp(to,i);
		}
	}
	return d;
}
void solve(){
	printf("%d
"
,DP(n,0)); int cur = 0; rep(i,1,n){ a[i] = from[n - i + 1][cur].se; cur = from[n - i + 1][cur].fi; } /* memset(f,-1,sizeof(f)); f[0][0] = 0; rep(i,0,n - 1){ rep(j,0,tot){ if ( f[i][j] == -1 ) continue; rep(k,0,9){ int to = trans[j][k] , len = n - i - 1; int d = f[i][j] + g[to][len]; if ( f[i + 1][to] < d ) f[i + 1][to] = d , pre[i + 1][to] = mp(j,k); } } } int ans = 0 , rec = 0; rep(i,0,tot){ if ( f[n][i] > ans ){ ans = f[n][i] , rec = i; } } printf("%d
",ans); repd(i,n,1){ a[i] = pre[i][rec].se; rec = pre[i][rec].fi; }*/
rep(i,1,n) printf("%d",a[i]); puts(""); } int main(){ freopen("input.txt","r",stdin); scanf("%s %s %d",s1 + 1,s2 + 1,&n); lenl = strlen(s1 + 1) , lenr = strlen(s2 + 1); init(); build(); solve(); }

1110G - Tree-Tac-Toe
제목: 나무 한 그루를 주는데 그 위에 흰 점과 염색하지 않은 점이 있고 흰색이 먼저 손을 잡고 번갈아 염색한다.세 개의 연속 백점으로 염색하면 이긴다.무승부냐, 백승이냐.n<=5e5 욕심 좋아!우선 화이트 포인트를 무색으로 바꿔주세요.가점은 같은 염색을 한 후 선후손이 변하지 않고 상태가 이전과 일치할 것을 보증한다.이렇게 전환되어 분류 토론의 상황을 크게 감소시켰다.전환하지 않아도 토론할 수 있다.하지만 전환 후 모델은 훨씬 간단합니다!
이어서 특수 상황의 분류 토론을 진행한다.시험장에서 너무 흐리멍덩하게 생각해서 뼈형에 중간점이 홀수인 경우(당시 중간점만 논의했는데 확장이 가능할 줄은 몰랐다) 자신의 알고리즘을 확인할 때 더욱 꼼꼼해야 한다. 물론 이런 사고는 많이 단련해야 한다!
my code
1110F - Nearest Leaf
제목: dfs 순서에 따라 표시된 나무를 제시하고 점 거리 [l,r]에서 가장 가까운 잎의 거리를 묻는다.
이 문제를 직접 풀면 lca가 어디에 있는지 모르기 때문에 유지하기 어렵고 dfs 서열이 정해져 있어 점분과 중연쇄 분할을 할 수 없다.이때 오프라인을 고려하여 (원래 명백한 사고방식을 들었기 때문에 시험장에서 wxh를 물어서야 비로소 생각났다.) 각 점에서 모든 잎사귀까지의 거리를 직접 유지하고 질문을 통일적으로 처리하면 된다.
1110E - Magic Stones
의미: 시퀀스 c[i]를 조작할 수 있음: 위치 i를 선택하고, (2 < = i < = n - 1) c[i]를 c [i + 1] + c [i 1] + c [i 1 1] - - c [i 1] - c [i 1] - c [i 1] - c [i 1] + c [i + 1] + c [i + 1] + c [i - i - 1] - c [i] - c [i] - i] - i[i] 위치 i, (2 < = i < n = 1]]]] 위치 i, (2 < = i< = i = i = i = i]를 선택하고, c[i]]를 [i] + 1]로 바꾸고, c[i]를 [i] [i] [i] [i] [i] [i]]
매번 조작은 차분수 그룹을 위치를 바꾸려고 할 때 문제가 비교적 차분 서열로 바뀌어 순서가 같은지 첫 번째 요소와 같은지 여부가 분명하다. 만약 상술한 것이 같으면 원 서열은 같다.또한 마지막 원소 c[n]=sigma(d[i])+c[1]는 차분수 그룹의 순서에 따라 바뀌지 않으며 특판할 필요가 없다.판단 서열이 같은 사고방식은 항상 차분이나 접두어와 판단으로 바뀐다!
1110D - Jongmah
제목: n개의 숫자를 제시하면 두 가지 삼원조(i, i+1, i+2)를 구성할 수 있고, (i, i, i)는 최대 몇 개의 삼원조를 구성할 수 있느냐고 묻는다.
처음엔 1e6 보고 욕심인 줄 알았는데사실 간단해야 할 dp(동료에게 물었다)는 3개가 넘는 중복된 순자를 3개의 삼원조로 직접 대체하기 때문에 순자의 개수인%3을 기록하면 된다.f(i, 0... 2, 0... 2)는 i로 시작하고 i가 중간에 있는 순자 개수를 나타낸다.간단하게 옮기면 된다.불법 상태를 버리지 않도록 주의하시오
매우 간단해 보이는 모형으로 때로는 욕심으로, 때로는 dp로 처리한다.축적된 것이 너무 적으니 총결과 융합이 관통되고 성질을 찾는 것을 배워야 한다!

좋은 웹페이지 즐겨찾기