一些思維題記(長期更新)

A. Prime Subtraction Codeforces 1238A

題意: 給出兩個數A,BA,B,詢問 AB|A-B|是否是素數的倍數。
思路:
這題涉及一點小數論,每個數都能進行質因數分解(除了1),所以只要A-B不爲1就輸出YES,否則輸出NO

B. Kill 'Em All 1238B

題意:
在座標xx的地方扔炸彈,位於xx的地方的怪會直接去世,若不位於,則會被爆炸衝擊波擊退 kk個單位

思路: 排序去重,從最大的xx開始扔炸彈即可。

C. Standard Free2play (模擬)

題意: 一個人位於hh的板子上,通過一些操作(拉動拉桿,使得 hh1h和h-1的踏板狀態改變,如果原來是出來的,現在收回去),或者通過使用石頭使得任意的踏板改變狀態,達到高度00,問最小用多少個石頭。

思路: 如果直接模擬h (1e9)會超時,注意到告訴你踏板的狀態只有n(1e5),於是就從這個角度入手。
看下一個踏板的高度和當前高度,如果說下一個踏板的高度不是 nowHeight1nowHeight-1,那麼可以直接從hh高度跳到Hnxt1H_{nxt}-1,反之需要判斷以下,具體看代碼

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
int arr[maxn];
int main()
{
    int q;  cin >> q;
    while(q--){
        int h,n;    cin >> h >> n;
        for(int i = 0; i < n; ++i){
            cin >> arr[i];
        }
        int now = h,ans = 0;
        for(int i = 1; i < n;){
            if(now<=2)  break;
            if(arr[i]==now-1){
                if(i+1 < n&&arr[i+1]==now-2){
                    i+=2;   now = now-2; continue;   // 到下一個
                }else{
                    ++ans,now = now-2,++i;
                }
            }else if(arr[i]!=now-1){
                now = arr[i]+1;
            }
        }
        cout << ans << endl;
    }
    return 0;
}

D. AB-string 1238D
去除掉 “AAAAB",“BBBBA” 類似的情況就可以了。

C. Registration system

思路:map記錄即可。

#include <bits/stdc++.h>
using namespace std;
map<string,int> mp;
int main()
{
	int n;	cin >> n;
	for(int i = 0; i < n; ++i){
		string str;	cin >> str;
		if(!mp.count(str)){
			cout << "OK" << endl;
			mp[str]++;
		}else{
			cout << str << mp[str]++ << endl;
		}
	}
	return 0;
}

A. Two Substrings
題意:問字符串裏有沒有ABAB,BABA
思路:暴力亂搞

#include <bits/stdc++.h>
using namespace std;
map<string,int> mp;
int main()
{
	string str;	cin >> str;
	bool isok1 = false,isok2 = false;
	for(int i = 0,n = str.size(); i < n; ++i){
		if(i+1<n && str[i]=='A' && str[i+1]=='B'){
			for(int j = i+2; j < str.size(); ++j){
				if(j+1 < n&& str[j]=='B' && str[j+1]=='A'){
					cout << "YES" << endl;
					return 0;
				}
			}
		}
		else if(i+1<n && str[i]=='B' && str[i+1]=='A'){
			for(int j = i+2; j < str.size(); ++j){
				if(j+1 < n&& str[j]=='A' && str[j+1]=='B'){
					cout << "YES" << endl;
					return 0;
				}
			}			
		}
	}
	cout << "NO" << endl;
	return 0;
}

B. Minimum Ternary Strings

思路:可以發現1的位置是任意的,所以貪心的考慮即可

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string str; cin >> str;
    string ans;
    int one = 0;
    for(int i = 0,n = str.size(); i < n; ++i){
        if(str[i]=='1') one++;
        else ans += str[i];
    }
    bool isprint = false;
    for(int i = 0,n = ans.size(); i < n; ++i){
        if(ans[i]=='0'){
            cout << ans[i];
        }else if(ans[i]=='2'){
            if(!isprint){
                for(int j = 0; j < one; ++j)    cout << '1';
                isprint = true;
            }
            cout << ans[i];
        }
    }
    if(!isprint){
        cout << string(one,'1');
    }
    cout << endl;
    return 0;
}

E. Military Problem

詢問:(u,k) 從u開始第k個被dfs到的點是什麼

思路: DFS序的應用

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
vector<int> edge[maxn];
int dfn[maxn],siz[maxn];  bool vis[maxn];
int cnt = 0;
int pos[maxn];
void dfs(int u,int fa){
    dfn[++cnt] = u;
    pos[u] = cnt;
    vis[u] = true;
    siz[u] = 1;
    for(int i = 0; i < edge[u].size(); ++i){
        if(!vis[edge[u][i]]&& edge[u][i]!=fa){
            dfs(edge[u][i],u);
            siz[u] += siz[edge[u][i]];
        }
    }
}
int main()
{
    int n,q;    cin >> n >> q;
    for(int i = 2,x; i <= n; ++i){
        cin >> x;   edge[x].push_back(i);
    }
    dfs(1,0);
    for(int i = 0; i < q; ++i){
        int u,k;    cin >> u >> k;
        if(k > siz[u]){cout << -1 << endl;}
        else cout << dfn[pos[u] + k - 1] << endl;
    }
    return 0;
}

1234D - Distinct Characters Queries (線段樹維護區間內不同字母的二進制)
思路:因爲最多26個字母,所以用一個26位的二進制數來表示區間有哪些字母,合併區間的時候用或操作就可以。(第一次知道線段樹還能這麼整)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
struct Tree{
    int bit;
}tree[maxn<<2];
inline int lson(int root){return root << 1;}
inline int rson(int root){return root << 1|1;}
inline void push_up(int root){
    tree[root].bit = tree[lson(root)].bit | tree[rson(root)].bit;
}
void BuildTree(int l,int r,int root,string str){
    if(l==r){
        tree[root].bit = 1 << (str[l-1]-'a');
 
       // cout << l <<' '<< tree[root].bit << endl;
        return;
    }
    int mid = l + r >> 1;
    BuildTree(l,mid,lson(root),str);
    BuildTree(mid+1,r,rson(root),str);
    push_up(root);
}
void update(int l,int r,int pos,int root,char c){
    if(l==r){
        tree[root].bit = 1 << (c - 'a');
        return;
    }
    int mid = l + r >> 1;
    if(pos <= mid)    update(l,mid,pos,lson(root),c);
    else update(mid+1,r,pos,rson(root),c);
    push_up(root);
}
int query(int l,int r,int ql,int qr,int root){
    if(ql <= l && r <= qr){
        return tree[root].bit;
    }
    int mid = l + r >>   1;
    int ans = 0;
 
 
    if(ql <= mid){
        ans |= query(l,mid,ql,qr,lson(root));
    }
    if(qr > mid){
        ans |= query(mid+1,r,ql,qr,rson(root));
    }
    return ans;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);	cout.tie(0);
    string str; cin >> str;
    BuildTree(1,str.size(),1,str);
    int n;  cin >> n;
    for(int i = 0; i < n; ++i){
        int op,l,r,pos; char c;
        cin >> op;
 
        if(op==1){
            cin >> pos >> c;
            update(1,str.size(),pos,1,c);
        }else{
            cin >> l >> r;
            int cnt = query(1,str.size(),l,r,1),ans = 0;
            // cout << cnt << endl;
            for(int i = 0; i < 26; ++i){
                if(cnt & 1)
                    ++ans;
				cnt >>=1;
            }
            cout << ans << '\n';
        }
    }
 
    return 0;
}

1219C - Periodic integer number 字符串構造(多種情況考慮)
思路:對於這種構造模擬題最好還是在紙上把情況都列出來,直接敲容易遺漏…
具體看代碼,主要是區分 lenmod  n==0len \mod n==0lenmod  n!=0len\mod n !=0的情況

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int n;	cin >> n;
	string str;	cin >> str;
	int len = str.size();
	if(len%n!=0){
		string temp;
		temp += '1';
		temp += string(n-1,'0');
		for(int i = 0,x = int(ceil(len*1.0/n)); i < x; ++i){
			cout << temp;
		}
		cout << endl;
	}else{
		string temp = str.substr(0,n);
		bool isbig = false;
		for(int i = n; i < len; i+=n){
			for(int j = 0; j < n; ++j){
				if(str[i+j] < temp[j]){
					isbig = true;
				}else if(str[i+j]>temp[j])  break;
			}
		}
		int jin = 0;
		if(!isbig){ // 就說明是循環節類型
			temp[n-1] = temp[n-1] + 1;
			jin = (temp[n-1] - '0')/10;
			temp[n-1] = (temp[n-1] - '0')%10 + '0';
			if(jin){
				for(int i = n-2; i >= 0; --i){
					temp[i] = temp[i] + jin;
					jin = (temp[i] - '0')/10;
					temp[i] = (temp[i] - '0')%10 + '0';
					if(jin==0)	break;
				}
			}
		}
		//cout << temp << endl;
 
		for(int i = 0,x = len/n+jin; i < x; ++i){
			if(jin)	cout << '1' << temp.substr(1,n-1);
			else cout << temp;
		}
 
		cout << endl;
	}
	return 0;
}

1218F Workout plan (簡單的貪心)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1e5+5;
ll arr[maxn],money[maxn];
set<ll> st;
int main()
{
    ll n,k;    cin >> n >> k;
    for(ll i = 0; i < n; ++i)  cin >> arr[i];
    ll A;  cin >> A;
    for(ll i = 0; i < n; ++i)  cin >> money[i];
    ll ans = 0;    bool isok = true;
    for(ll i = 0; i < n; ++i){
        if(k >= arr[i]){
            st.insert(money[i]);
        }else{
            st.insert(money[i]);
            while(k < arr[i] && !st.empty()){
                k += A;
                ans += *st.begin();
                st.erase(st.begin());
            }
            if(k < arr[i]){
                isok = false;
                break;
            }
        }
    }
    if(isok)    cout << ans << endl;
    else cout << -1 << endl;
    return 0;
}

F2. Same Sum Blocks (Hard) (STL+BruteForce+Greedy)

#include <iostream>
#include <set>
#include <map>
#include <algorithm>
#include <vector>
using namespace std;
const int MAX = 1505;
int arr[MAX];
struct query{
    int l,r;
    bool operator < (const query & h){
        return r == h.r? l < h.l : r < h.r;
    }
}Query[MAX*MAX];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int n;  cin >> n;
    for(int i = 1; i <= n; ++i){
        cin >> arr[i];
    }
    set<int>st;
    map<int,vector<query> > mp;
    int tot = 0;
    for(int i = 1; i <= n; ++i){
        int sum = arr[i];
        st.insert(sum);
        mp[sum].push_back(query{i,i});
        for(int j = i+1; j <= n; ++j){
            sum+=arr[j];
            st.insert(sum);
            mp[sum].push_back(query{i,j});
        }
    }
    vector<query> vec;
    for(auto i : st){
        sort(mp[i].begin(),mp[i].end());
        vector<query>tt;
        int r = -1;
        for(auto j : mp[i]){
            query t = j;
            if(t.l > r ){
                r = t.r;
                tt.push_back(t);
            }
        }
        if(tt.size() > vec.size()) vec = tt;
    }
    cout << vec.size() <<endl;
    for(int i = 0; i < vec.size(); ++i){
        cout << vec[i].l << ' ' << vec[i].r<<endl;
    }
    return 0;
}
 

Codeforces Round #509 (Div. 2) E.Tree Reconstruction(思維,構造)

思路:
很容易發現,一個樹,刪掉一條邊之後,其中一棵子樹的權值一定是n,所以先看輸入的maxa,maxb 中 maxb是不是爲n,如果不是,就可以直接輸出NO了。
然後對於 maxa,統計一下maxa出現的個數,然後往 maxa-maxb之間插入點就可以了。注意一下細節即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+5;
map<int,int> mp;
vector<pair<int,int>> vec;
bool vis[maxn];
int main()
{
	int n;	cin >> n;
	bool isok = true;
	for(int i = 0,a,b; i < n-1; ++i){   // b 只能爲 n
		cin >> a >> b;
		mp[a]++;
		if(b!=n)	isok = false;
	}
	if(!isok){
		cout << "NO" << endl;
		return 0;
	}
	for(auto i : mp){
		vis[i.first] = 1;
		if(i.second > i.first){
			cout << "NO" << endl;
			return 0;
		}
		int cnt = 1;
		int now = i.first;
		for(int j = 1; j < i.first && cnt < i.second; ++j){
			if(vis[j])	continue;
			vis[j] = true;	vec.push_back(make_pair(now,j));
			now = j;	cnt++;
		}
		vec.push_back(make_pair(now,n));	vis[now] = 1;
		if(cnt!=i.second){
			cout << "NO" << endl;
			return 0;
		}

	}
	cout << "YES" << endl;
	for(auto i : vec){
		cout << i.first << ' ' << i.second << endl;
	}
	return 0;
}

B. Chemical table 並查集

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
int pre[maxn<<1];
int FindPre(int x){
    return pre[x] == x? x : pre[x] = FindPre(pre[x]);
}
inline void Union(int x,int y){
    int fx = FindPre(x),fy = FindPre(y);
    if(fx!=fy) pre[fy] = fx;
}
bool vis[maxn<<1];
int main()
{
    int n,m,q;  cin >> n >> m >> q;
    for(int i = 1; i <= n+m; ++i)   pre[i] = i;
    for(int i = 0; i < q; ++i){
        int r,c;    cin >> r >> c;
        c += n;
        Union(r,c);
    }
    int ans = -1;
    for(int i = 1; i <= n+m; ++i){
        int root = FindPre(i);
        if(!vis[root]){
            vis[root] = true;
            ans++;
        }
    }
    cout << ans << endl;
    return 0;
}

update (2019/11/22)
分治: Codeforces 448C

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e3+5;
const int INF = 0x3f3f3f3f;
int arr[maxn];
int n;
inline int DC(int l,int r,int now){
    if(r-l==1)    return 1;
    int minn = INF;
    for(int i = l; i < r; ++i) minn = min(minn,arr[i]);
    int ans = minn - now;
    for(int i = l,j; i < r; ++i){
        if(arr[i] > minn){
            for(j = i; j < r && arr[j] > minn; ++j);
            ans += DC(i,j,minn);
            i = j;
        }
    }
    return min(r-l,ans);
}
int main()
{
    ios::sync_with_stdio(false);    cin.tie(0); cout.tie(0);
    cin >> n;
    for(int i = 0; i < n; ++i){
        cin >> arr[i];
    }
    cout << DC(0,n,0) << endl;
    return 0;
}

260A - Adding Digits(思維題)
可以先遍歷0~9,加到a的右邊看一下是不是能被b整除,如果可以的話,後面的n-1個數都補0即可。

1255D - Feeding Chicken
分析:要把土地分成k塊,使得每塊之間的權值差距最小,我們可以先把總權值算出來,然後平均分配即可,然後就遍歷整個矩陣,給其染色就可以了

#include <bits/stdc++.h>
using namespace std;
const int maxn = 105;
char color[maxn];
int arr[maxn];
char G[105][105];
int main()
{
    ios::sync_with_stdio(false);    cin.tie(0); cout.tie(0);
    int T;  cin>>T;
    for(int i = 0; i < 10; ++i) color[i] = i + '0';
    for(int i = 10,j = 0; i <= 62; i+=2,++j)   color[i] = 'A'+j,color[i+1] = 'a'+j;
    while(T--){
        int r,c,k;  cin >> r >> c >> k; int cnt = 0;
        for(int i = 0; i < r; ++i){
            for(int j = 0; j < c; ++j){
                cin >>G[i][j];  if(G[i][j]=='R')    ++cnt;
            }
        }
        int num = cnt/k;
        for(int i = 0; i < k; ++i)  arr[i] = num;
        for(int i = 0; i < cnt%k; ++i)  arr[i] += 1;
        int now = 0;
        bool isok  = false;;
        for(int i = 0; i < r; ++i){
            if(isok){
                for(int j = 0; j < c; ++j){
                    if(G[i][j]=='R')    arr[now]--;
                    G[i][j] = color[now];
                    if(arr[now]==0 && now < k-1) ++now;
                }
            }
            else{
                for(int j = c-1; j >= 0; --j){
                    if(G[i][j]=='R')    arr[now]--;
                    G[i][j] = color[now];
                    if(arr[now]==0 && now < k-1) ++now;
                }
            }
            isok = !isok;
        }
        for(int i = 0; i < r; ++i){
            for(int j = 0; j < c; ++j)  cout << G[i][j];
            cout << endl;
        }
 
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章