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和?只能被使用一次,又是一个匹配问题,因此我们考虑最大流拆点。