D - Change Usernames (atcoder.jp)
(1)题目大意
每个用户都要改变自己的名称从A-B,但是他们不想自己改的名称被别人用掉了,因此让你判断是否可以改。
(2)解题思路
这种类似于匹配的问题,可以想到并查集,我们可以先hash每个名称,然后判断是否有两个名称出现在同一集合即可。
(3)代码实现
#include "bits/stdc++.h"
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define ll long long
#define db double
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 2e5 + 10;
unordered_map<string,int> mp;
int cnt;
struct UFS {
int f[N],siz[N];
void init(int n) {for(int i=1;i<=n;i++)siz[i]=1,f[i]=i;}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
bool same(int x,int y){return find(x)==find(y);}
void merge(int x,int y) {if(!same(x,y))siz[find(y)]+=siz[find(x)],f[find(x)]=find(y);}
int qsz(int x){return siz[find(x)];}
}comb;
int get(string s)
{
if(!mp.count(s)) mp[s]=++cnt;
return mp[s];
}
void solve()
{
int n;
cin>>n;
comb.init(2*n);
bool ok=true;
rep(i,1,n) {
string s1,s2;
cin>>s1>>s2;
int x=get(s1),y=get(s2);
if(comb.same(x,y)) ok=false;
else comb.merge(x,y);
}
if(ok) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T = 1;
// cin >> T;
while(T --) solve();
return 0;
}
(1)题目大意
现在有n天,若当天放假生产力则为0,否则为a[i],定义两个假期之间的生产效率为,其中n为距离。
(2)解题思路
我们考虑dp[i][j]表示当前是第i天,已经连续工作了j天的效率最大为多少。
那么就有dp[i][j] = max(dp[i][j],dp[i-1][j-1])表示当前为工作日
dp[i][0]=max(dp[i-1][j-1]+s[j-1],dp[i][0])表示当前为假期,前面已经有j-1天工作了的效率。
注意最后一天为假期我们的dp值是没有更新的,因此我们取答案的时候要加上s[i]。
(3)代码实现
#include "bits/stdc++.h"
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define ll long long
#define db double
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 5010;
ll s[N],dp[N][N],a[N];
void solve()
{
int n;
cin>>n;
rep(i,1,n) cin>>a[i],s[i]=s[i-1]+(a[(i+1)>>1]);
rep(i,1,n) rep(j,1,i) {
dp[i][j]=max(dp[i-1][j-1],dp[i][j]);
dp[i][0]=max(dp[i-1][j-1]+s[j-1],dp[i][0]);
}
ll ans=0;
rep(i,1,n) ans=max(ans,dp[n][i]+s[i-1]);
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T = 1;
// cin >> T;
while(T --) solve();
return 0;
}
F - Substring of Sorted String (atcoder.jp)
(1)题目大意
给你一个长度为N的串S,第一个操作是把第x个字符换成c,第二个操作是询问[l,r]这个串是否为原串排序后的子串。
(2)解题思路
考虑若[l,r]串若能成为原串排序后子串,有以下两个条件。
1.[l,r]的逆序对数量为0
2.[l,r]除了首尾字母的数量可以少于原串,中间的必须要和原串相同。
我们可以想到第一个条件可以用逆序对的方式用树状数组处理出来。
第二个条件我们也可以开26个树状数组统计。
(3)代码实现
#include "bits/stdc++.h"
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define ll long long
#define db double
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl
#define no cout << "NO" << endl
#define lowbit(x) x&-x
using namespace std;
const int N = 2e5 + 10;
char s[N];
int seg[28][N],cnt[26],n;
void add(int p,int x,int v)
{
while(x<=n) {
seg[p][x] += v;
x += lowbit(x);
}
}
int qry(int p,int x)
{
int res=0;
while(x>=1) {
res += seg[p][x];
x -= lowbit(x);
}
return res;
}
void solve()
{
scanf("%d%s",&n,s+1);
rep(i,1,n) {
add(s[i]-'a',i,1);
if(i>1&&s[i]<s[i-1]) add(27,i,1);
}
int q;
char ch;
scanf("%d",&q);
while(q--) {
int op,l,r;
scanf("%d",&op);
if(op==1) {
scanf("%d %c",&l,&ch);
char vm = s[l];
if(l>1&&s[l]<s[l-1]) add(27,l,-1);
if(l<n&&s[l]>s[l+1]) add(27,l+1,-1);
s[l] = ch;
if(l>1&&s[l]<s[l-1]) add(27,l,1);
if(l<n&&s[l]>s[l+1]) add(27,l+1,1);
add(vm-'a',l,-1);add(s[l]-'a',l,1);
}
else {
scanf("%d%d",&l,&r);
if(qry(27,r)-qry(27,l)) puts("No");
else {
bool ok=true;
rep(j,s[l]-'a'+1,s[r]-'a'-1) {
cnt[j]=qry(j,r)-qry(j,l-1);
if(cnt[j]!=qry(j,n)) {
ok=false;
break;
}
}
if(ok) puts("Yes");
else puts("No");
}
}
}
}
int main()
{
int T = 1;
while(T --) solve();
return 0;
}
(1)题目大意
给你一个W*H的二维矩阵,对于每个1,必须有1个1*1的方块覆盖,每个2,必须由1*2或者2*1的方块覆盖,?可以被1*1或者1*2或者2*1的方块覆盖,问最后能否使这个矩阵被完全覆盖。
(2)解题思路
很容易想到1在这个矩阵没啥限制,因此不用管1,只需要管2和?的匹配,由于每一个2和?只能被使用一次,又是一个匹配问题,因此我们考虑最大流拆点。
把每个2和问号拆成入点和出点。
若当前为2,则源点向当前点的入点加一条容量为1的管道,并从当前点的出点向汇点加一条容量为1的管道,并且向四个方向不为1的点用出点向他们的入点连一条边。
若当前为?,则直接向汇点连一条容量为1的管道。
(3)代码实现
#include <bits/stdc++.h>
#define ll long long
const int inf = 0x3f3f3f3f;
//要保证源点和汇点联通
using T = long long;
struct HLPP {
struct Edge {
int j, q;
T x;
};
int N, K = 0, m = 0, cnt = 0;
std::vector<std::vector<Edge>> G;
std::vector<int> H, p1;
std::vector<T> X;
std::vector<std::vector<int>> Q;
HLPP(int nn) : N(nn), G(N + 1), H(N + 1), p1(N + 1), X(N + 1), Q(N * 2 + 2) {}
void add(int i, int j, T x, T y = 0) {
int p = G[i].size(), q = G[j].size();
G[i].push_back({j, q, x});
G[j].push_back({i, p, y});
}
void push(int i) {
Q[H[i]].push_back(i);
m = std::max(m, H[i]);
}
void relabel(int t) {
cnt = 0;
for (auto &q : Q) q.clear();
fill(H.begin(), H.end(), N * 2 + 1);
std::vector<int> Q(N);
int s = -1, e = -1;
H[Q[++e] = t] = 0;
while (s < e) {
int i = Q[++s], h = H[i] + 1;
for (auto &[j, q, x] : G[i])
if (G[j][q].x && h < H[j]) {
H[Q[++e] = j] = h;
if (X[j] > 0) push(j);
}
}
}
void discharge(int i) {
auto &v = X[i];
int h = N * 2;
for (int &p = p1[i], m = G[i].size(); m--; p = (p ? : G[i].size()) - 1) {
auto &[j, q, x] = G[i][p];
if (!x) continue;
if (H[i] != H[j] + 1) {
h = std::min(h, H[j] + 1);
continue;
}
auto f = std::min(x, v);
x -= f, v -= f;
if (!X[j]) push(j);
X[j] += f, G[j][q].x += f;
if (!v) return;
}
cnt++;
H[i] = h;
if (H[i] < N && X[i] > 0) push(i);
}
T max_flow(int s, int t, T inf = std::numeric_limits<T>::max()) {
add(s, t, 1);relabel(t);push(s);
X[s] = inf, X[t] = -inf;
for (; ~m; m--)
while (Q[m].size()) {
int i = Q[m].back();
Q[m].pop_back();
if (H[i] == m) discharge(i);
if (cnt >= 4 * N) relabel(t);
}
return X[t] + inf - 1;
}
};
char mp[310][310];
int n,m,mx[4]={1,-1,0,0},my[4]={0,0,1,-1};
int get(int i,int j,int t)
{
return t*n*m + i*m+j;
}
int main()
{
scanf("%d%d",&n,&m);
HLPP f(2*n*m+10);
for(int i=0;i<n;i++) scanf("%s",mp[i]);
int tot=0,S=2*n*m+1,T=2*n*m+2;
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
if(mp[i][j]=='1') continue;
if(mp[i][j]=='2'){
tot++;
f.add(S,get(i,j,0),1);
for(int k=0;k<4;k++) {
int dx=i+mx[k],dy=j+my[k];
if(dx<0||dx>=n||dy<0||dy>=m) continue;
if(mp[dx][dy]=='1') continue;
f.add(get(i,j,0),get(dx,dy,1),1);
}
}
f.add(get(i,j,1),T,1);
}
}
if(tot==f.max_flow(S,T)) puts("Yes");
else puts("No");
return 0;
}