AtCoder Beginner Contest 285(B,D,E,F)
B (暴力,非二分)
这道题其实很简单,但是我在\(vp\)的过程,有了一个错误的认识,纠正一下
那就是,我把这个当成了一个二分题,并且还有点坚定不移,后来细想,发现不对
二分,适用于那种边界分明的那种题(左边一定是符合条件,右边一定符合条件,也可表达为线性问题那种)这种的,但是这个题不符合这个条件,不符合(万一右边出现了一个符合条件的,但是左边也可能存在不符合条件的)
所以这道题直接暴力即可
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
using namespace std;
#define int long long
#define LL long long
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const double eps=1e-9;
const int maxn=1e6+10;
const int mod=998244353;
int n;
string s;
int solve(int pos)
{
int ans=n-pos;
for (int i=1;i<=n-pos;i++)
{
if(s[i]==s[i+pos])
{
ans=i-1;
break;
}
}
return ans;
}
signed main()
{
cin>>n>>s;
s=" "+s;
for (int i=1;i<n;i++)
{
cout<<solve(i)<<"\n";
}
system ("pause");
return 0;
}
D (图,拓扑排序)
为什么每次我都没有看懂题意,好难过
这个题的大意就是每个人都会使用一个字符串\(s\),但是每个人都想要换这个字符串\(s\)换成\(t\),但是这个换字符串还有一个条件很关键,那就是那个\(t\)是没有正在被其他人所使用的
题目问是否可以让每个人都可以换成功(我一开始以为是只要一个人换成功就好了,我就在想,怎么会有这么简单的\(D\)题)
正难则反,我们不太可能找到一个正确的换字符串的顺序,我们可以找有哪些是一定换不了的
然后,我们发现这个换来换去的有点像图,如果把这个过程当成图来看(有向边),如果有一个环的话,那么这个环里面的字符都是换不成功的了,所以我们只需要找到环即可(找到,就是\(No\))
对于找环,有两种方法
一种是直接\(dfs\),如果出现了一个点到了\(2\)次以上,那么一定存在一个环
一种是拓扑排序,判断进入队列里面是否有\(n\)个
题目里面的字符串我对他们进行了离散化
我这里用的是拓扑排序
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
using namespace std;
#define int long long
#define LL long long
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const double eps=1e-9;
const int maxn=1e6+10;
const int mod=998244353;
int n;
string s[maxn],t[maxn];
set<string>rk;
map<string,int>has;
int in[maxn];
vector<int>g[maxn];
signed main()
{
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>s[i]>>t[i];
rk.insert(s[i]);
rk.insert(t[i]);
}
int now=0;
for (auto x:rk)
{
now++;
has[x]=now;
}
for (int i=1;i<=n;i++)
{
int u=has[s[i]],v=has[t[i]];
g[u].push_back(v);
in[v]++;
}
queue<int>q;
int cnt=now;
for (int i=1;i<=now;i++)
{
if(in[i]==0)
{
q.push(i);
cnt--;
}
}
while (!q.empty())
{
int u=q.front();
q.pop();
for (auto x:g[u])
{
in[x]--;
if(in[x]==0)
{
q.push(x);
cnt--;
}
}
}
if(cnt)
{
cout<<"No\n";
}
else
{
cout<<"Yes\n";
}
system ("pause");
return 0;
}
E(dp,前缀和)
这个题目的大意就是有n天,我们可以选择任意天作为假期,我们每一天都会有一个效率
对于这一天是假期,那么这一天的效率为\(0\)
对于这一天是工作日,那么我们需要知道上一次假期离现在的天数\(x\),还需要知道现在距离下一次假期的天数,那么这一天的效率为\(A_{min(x,y)}\)
我们发现假期具体是哪一天不重要,重要的是这一天距离自己较近的那一天的距离是多少
所以干脆把第一天作为作为上一次工作的假期,这样就不用了担心后面寻找前一个不太好找了
然后我们可以设\(dp[i]\)为前\(i\)天,并且第\(i\)天是假期的最大效率
可以得到状态转移方程为
dp[i]=max(dp[i],dp[j]+(a[min(i-(j+1),(j+1)-j)]+a[min(i-(j+2),(j+2)-j]+....+a[min(i-(i-1),(i-1)-j)]+dp[j]))
我们发现那一段\(a\)的和好像是有规律的,对于那些里\(i\)近的,选择\(i\),可以是从\(1\)到中间,对于那些里\(j\)近的,选择\(j\),可以是从\(1\)到中间,但是注意最中间的那一个,离\(i\)和\(j\)一样,只需要加一次即可,我们可以直接通过前缀和预处理出来
故,对于\(l,r\)范围,可以直接得到\(sum[len/2]+sum[(len+1)/2]\)
然后我们可以得到一个更简单的状态转移方程
dp[i]=max(dp[i],dp[j]+get(j,i))
具体看代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
using namespace std;
#define int long long
#define LL long long
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const double eps=1e-9;
const int maxn=1e6+10;
const int mod=998244353;
int n;
int a[maxn],sum[maxn];
int dp[maxn];
int get(int l,int r)
{
int len=(r-l-1);
int L=len/2,R=(len+1)/2;
return sum[L]+sum[R];
}
signed main()
{
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
dp[1]=0;
for (int i=2;i<=n+1;i++)
{
for (int j=1;j<i;j++)
{
dp[i]=max(dp[i],dp[j]+get(j,i));
}
}
cout<<dp[n+1]<<"\n";
system ("pause");
return 0;
}
F(树状数组)
这个题大意很简单,就是给你一个字符串,有两种操作
一种是需要把\(x\)位置的字符改成\(ch\)
还有一种是需要判断对于此时的字符串\(s\),把里面的字符按从小到大的顺序排列可以得到一个字符串\(t\),我们需要判断的就是此时的\(s\)的\(l\)到\(r\)这一段字符串是不是\(t\)的子串
由题可知,要想为子串,\(s[l...r]\)必须是从小到大的,而且除了最前面的(最小的)和最后面的(最大的)(对于子串,我们都很熟悉,就是一个串删除前面若干个,删除后面若干个),这里面的字符数量都必须和整个字符串里面的字符数量一样,而且还必须连续
我们知道字符的数量不是很大,而且每修改一次,区间里面的字符数量都会改变
所以我们这里给每一个字符都创建了一棵树,用来记录这个字符的分布情况
前面都是很典型的树状数组
但是还有一点需要注意,我们这里的连续的判断,就是每次更新现在的位置,通过现在的位置和该字符的数量,判断这一小段里面是不是都是这一个字符,注意更新最新位置
具体操作可看代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <unordered_map>
#include <array>
#include <cstring>
using namespace std;
#define int long long
#define LL long long
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define inf 1e18
#define INF 1e18
#define mem(a,b) memset((a),(b),sizeof(a))
const double eps=1e-9;
const int maxn=1e5+10;
const int mod=998244353;
int n,q;
string s;
int lowbit(int x)
{
return x&(-x);
}
struct tree
{
int bit[maxn];
void add(int x,int val)
{
while (x<=n)
{
bit[x]+=val;
x+=lowbit(x);
}
}
int query(int x)
{
int res=0;
while (x)
{
res+=bit[x];
x-=lowbit(x);
}
return res;
}
int Query(int l,int r)
{
return query(r)-query(l-1);
}
}tr[27];
signed main()
{
cin>>n;
cin>>s;
s=" "+s;
for (int i=1;i<=n;i++)
{
int now=s[i]-'a';
tr[now].add(i,1);
}
cin>>q;
while (q--)
{
int op;
cin>>op;
if(op==1)
{
int pos;
char ch;
cin>>pos>>ch;
int last=s[pos]-'a';
tr[last].add(pos,-1);
s[pos]=ch;
int now=s[pos]-'a';
tr[now].add(pos,1);
}
else
{
int l,r;
cin>>l>>r;
int mx=0,mi=26;
for (int i=0;i<26;i++)//还有这个寻找最大最小值,最好不要从字符串的l,r里面寻找,太慢了,我们只要知道这里面有没有这个字符即可
{
if(tr[i].Query(l,r)>0)
{
mx=max(mx,i);
mi=min(mi,i);
}
}
int pos=l;
bool yes=true;
for (int now=mi;now<=mx;now++)
{
int cnt=tr[now].Query(l,r);
if(now!=mi&&now!=mx)
{
int all=tr[now].Query(1,n);
if(cnt!=all)
{
yes=false;
break;
}
}
int ll=pos,rr=pos+cnt-1;
int tot=tr[now].Query(ll,rr);
if(tot!=cnt)
{
yes=false;
break;
}
pos=rr+1;//注意边界,是rr而不是ll
}
if(yes)
{
cout<<"Yes\n";
}
else
{
cout<<"No\n";
}
}
}
system ("pause");
return 0;
}
标签:AtCoder,const,Beginner,int,long,maxn,include,285,define
From: https://www.cnblogs.com/righting/p/17378427.html