A. Prime Subtraction Codeforces 1238A
题意: 给出两个数
A
,
B
A,B
A,B,询问
∣
A
−
B
∣
|A-B|
∣A−B∣是否是素数的倍数。
思路:
这题涉及一点小数论,每个数都能进行质因数分解(除了1),所以只要A-B不为1就输出YES,否则输出NO
B. Kill 'Em All 1238B
题意:
在坐标
x
x
x的地方扔炸弹,位于
x
x
x的地方的怪会直接去世,若不位于,则会被爆炸冲击波击退
k
k
k个单位
思路: 排序去重,从最大的 x x x开始扔炸弹即可。
C. Standard Free2play (模拟)
题意: 一个人位于 h h h的板子上,通过一些操作(拉动拉杆,使得 h 和 h − 1 h和h-1 h和h−1的踏板状态改变,如果原来是出来的,现在收回去),或者通过使用石头使得任意的踏板改变状态,达到高度 0 0 0,问最小用多少个石头。
思路: 如果直接模拟h (1e9)会超时,注意到告诉你踏板的状态只有n(1e5),于是就从这个角度入手。
看下一个踏板的高度和当前高度,如果说下一个踏板的高度不是
n
o
w
H
e
i
g
h
t
−
1
nowHeight-1
nowHeight−1,那么可以直接从
h
h
h高度跳到
H
n
x
t
−
1
H_{nxt}-1
Hnxt−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
题意:问字符串里有没有
A
B
AB
AB,
B
A
BA
BA
思路:暴力乱搞
#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 字符串构造(多种情况考虑)
思路:对于这种构造模拟题最好还是在纸上把情况都列出来,直接敲容易遗漏…
具体看代码,主要是区分
l
e
n
m
o
d
n
=
=
0
len \mod n==0
lenmodn==0 和
l
e
n
m
o
d
n
!
=
0
len\mod n !=0
lenmodn!=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;
}