DDJ Regular Contest Round#3 Tutorial
tags: brute force, number theory
窮舉所有區間,用 或以下的複雜度 判斷當下區間是不是質數,是就加上總和
複雜度
判斷質數教學: http://web.ntnu.edu.tw/~algo/Prime2.html#2
Solution
tags: brute force
爆搜剪枝
直接遞迴窮舉所有組合,
記得每次要先判斷當下要放的數字排在是否能排在前一個數字後面
不能最後窮舉完排列才檢查
由於多筆測資,可能會出現重複的詢問,如果每次都重新計算會TLE
因此算過的詢問要建表記起來,重複就直接查表
然後原題網址XD: https://codeforces.com/gym/103102/problem/I
Solution
tags: dsu, LCT
可以直接砸LCT
想想看,如果題目要求反過來把原本每個 變成 有沒有比較好做
如果有想到作法的話,那就可以直接從最後面反過來做回去,
把每個操作紀錄起來
接著把原本的圖變成最後的情況,然後反向依序做回來
用一個並查集維護是不是同一個水區
複雜度
並查集教學: https://cp-algorithms.com/data_structures/disjoint_set_union.html
Solution
#include<bits/stdc++.h>
#define MXN 2002
#define MXQ 100005
#define endl '\n'
using namespace std;
int n,m,q;
int ans[MXQ],f[MXN*MXN];
pair<int,int> query[MXQ];
bool v[MXN*MXN];
string land[MXN];
int find(int x){
return f[x] == x ? x : f[x] = find(f[x]);
}
void merge(int x,int y){
x = find(x),y =find(y);
if(x==y) return;
f[y]=x;
}
int toord(int x,int y){
return x*n+y;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
cin>>n>>m;
iota(f,f+n*m,0);
for(int i=0;i<n;i++) cin>>land[i];
cin>>q;
for(int i=0,a,b;i<q;i++){
cin>>a>>b;
--a,--b;
query[i]=make_pair(a,b);
land[a][b]='#';
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
v[toord(i,j)]=1;
if(!i && !j) continue;
if(land[i][j] == 'W'){
if(i && land[i-1][j]=='W') merge(toord(i,j),toord(i-1,j));
if(j && land[i][j-1]=='W') merge(toord(i,j),toord(i,j-1));
}
}
}
int sum=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(land[i][j]=='W'){
sum+=v[find(toord(i,j))];
v[find(toord(i,j))]=0;
}
}
}
ans[q-1]=sum;
for(int i=q-1;i>0;i--){
int a=query[i].first,b=query[i].second,cnt=0;
land[a][b]='W';
if(a && land[a-1][b]=='W'){
cnt+=find(toord(a-1,b)) != find(toord(a,b))
merge(find(toord(a-1,b)), find(toord(a,b)));
}
if(b && land[a][b-1]=='W'){
cnt+=find(toord(a,b-1)) != find(toord(a,b))
merge(find(toord(a,b-1)), find(toord(a,b)));
}
if(a+1<n && land[a+1][b]=='W'){
cnt+=find(toord(a+1,b)) != find(toord(a,b))
merge(find(toord(a+1,b)), find(toord(a,b)));
}
if(b+1<m && land[a][b+1]=='W'){
cnt+=find(toord(a,b+1)) != find(toord(a,b))
merge(find(toord(a,b+1)), find(toord(a,b)));
}
sum-=cnt-1;
ans[i-1]=sum;
}
for(int i=0;i<q;i++) cout<<ans[i]<<endl;
return 0;
}
tags: strings, manacher, palindrome tree
可以用 manacher 求出以每個字元為中心的最長回文長度
接著分奇數偶數兩種case做,
分別再記錄前綴和,可以達到 建表 查表
複雜度
如果懶得建表,也可以二分搜有幾個長度
複雜度
manacher教學: https://cp-algorithms.com/string/manacher.html
當然也可以直接砸回文樹,把每種狀態看他長度有多長就存起來,再 查表,有興趣的再自已去查
Solution
tags: brute force, meet in the middle
總共有8個變數,如果直接窮舉 複雜度是爛掉
先把式子簡化:
變成
接著可以用中間相遇法,先 窮舉前四個 所有組合答案存進去一個容器裡(可以用hashtable或者二分搜,用map會TLE)
再花 窮舉後四個 所有組合答案,每次 時間去查有幾個值等於的數量
記得要處理 要排除
複雜度
Solution