cf #617 C-E2
t3一直在想双指针,思路太沙雕正解就是用一个map<pair<int,int>,int>记录最后到达当前位置的是第几个字符,想法就是如果现在到达的位置之前也到达过,那么这段就可以删掉。然后使得可以删掉的长度大小最小,并记录对应的posl,posr。然后一些细节也弄了挺久,位置各种+1 -1的错...还是太菜了
#include<bits/stdc++.h>
using namespace std;
const int inf=200000+10;
map<pair<int,int>,int> mp; //***
int main()
{
string s;
int t,i,j,k,n,len,f,posl,posr;
//freopen("617c.txt","r",stdin);
cin>>t;
while (t--)
{
int min=inf;
pair<int,int> p=make_pair(0,0);//***
cin>>n;mp.clear();
cin>>s;len=s.length();
posl=-1;posr=-1;
mp[{p.first,p.second}]=0;
for (i=0;i<len;i++)
{
if (s[i]=='U') p.second++;
if (s[i]=='D') p.second--;
if (s[i]=='R') p.first++;
if (s[i]=='L') p.first--;
if (mp[{p.first,p.second}]!=0||(p.first==0&&p.second==0))
{
k=i-mp[{p.first,p.second}]+1;
if (k<min)
{
min=k;
posl=mp[{p.first,p.second}]+1;
posr=i+1;
}
}
mp[{p.first,p.second}]=i+1;
}
if (posl==-1&&posr==-1) cout<<-1<<endl;
else cout<<posl<<' '<<posr<<endl;
}
//fclose(stdin);
return 0;
}
D题其实比较水,对于当前的怪物,算最少要使用技能多少次才能拿分,然后排个序就完了
算使用技能次数的时候也弄错了一些小细节......
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200+10;
int h[maxn],cnt[maxn];
int main()
{
int n,a,b,k,i,j,ans,t,y;
scanf("%d%d%d%d",&n,&a,&b,&k);
for (i=1;i<=n;i++) scanf("%d",&h[i]);
memset(cnt,0,sizeof(cnt));
for (i=1;i<=n;i++)
{
if (h[i]<=a) continue;
t=h[i]%(a+b);
if (t>0&&t<=a) continue;
if (t==0)
{
if (b%a==0) cnt[i]=b/a;else cnt[i]=b/a+1;
continue;
}
if (t%a==0) cnt[i]=t/a-1;else cnt[i]=t/a;
}
//for (i=1;i<=n;i++) printf("%d ",cnt[i]);
sort(cnt+1,cnt+n+1);
i=j=0;
while (j<=k)
{
i++;if (i>n) break;
j+=cnt[i];
}
ans=i-1;printf("%d\n",ans);
return 0;
}
E1和E2
先看E2吧。结合题解有了自己的一点想法。首先找出原序列的最长严格下降子序列,设长度为m,那么就至少需要m种颜色了。如果颜色<=m-1种,这m个数必定有两个数同色,次序一定无法交换,所以最后序列肯定不是单调不降的。那么有m种颜色就可以划分了。因为根据dilworth定理(emmm不太会证,但是知道这个结论),原序列可以划分成m个不下降子序列,然后给每个不下降子序列染成相同的颜色就行了。其实这道题的本质就是最少能划分成多少个不下降子序列。
有两个有点巧的地方:
一是虽然n<=100000,看上去直接求个lis复杂度不太行,然后nlogn的lis保存方案也好烦。但是每个元素的范围只有1-26,所以可以用pos[i](1<=i<=26)保存i出现的最后一个位置,因为相同的元素,位置越靠后的,这个位置能连的下降子序列就越长。这样时间复杂度只有O(26n)。二是染色的时候只要染成下降子序列dp数组的元素值就行了(这个一开始没想到)。因为dp数组的最大值为m,然后如果元素相同,就一定是单调不降的。这样刚好划分成m个不下降子序列
代码超级短:
#include<bits/stdc++.h>
using namespace std;
const int maxn=200+10;
int dp[maxn],pos[30],a[maxn]; //pos[i]:字符i(1-26)的最后一个位置
string s;
int i,j,k,t,n;
int main()
{
std::ios::sync_with_stdio(false);
cin>>n>>s;
for (i=0;i<n;i++)
a[i+1]=s[i]-'a'+1;
memset(dp,0,sizeof(dp));
memset(pos,0,sizeof(pos));
dp[1]=1;pos[a[1]]=1;
for (i=2;i<=n;i++){
dp[i]=1;
for (j=1;j<=26;j++)
if (pos[j]>0&&j>a[i]) dp[i]=max(dp[i],dp[pos[j]]+1);
pos[a[i]]=i;
}
int ans=0;
for (i=1;i<=n;i++) ans=max(dp[i],ans);
cout<<ans<<endl;
for (i=1;i<=n-1;i++) cout<<dp[i]<<' ';
cout<<dp[n]<<endl;
return 0;
}
然后看E1。E1就是问能不能染成两种颜色,当然可以用E2的方法做,而且E1的n<200,直接求下降子序列就行了。但是题解给出了一个贪心的方法感觉挺神奇的,脑补一下感觉挺对的:设已经有两个子序列,如果一个新的元素>=子序列一的末位,就把它连到一后面,如果>=二的末位就连到二后面,否则无解......
#include<bits/stdc++.h>
using namespace std;
string s,ans;
int main()
{
int i,j,n,f;
cin>>n>>s;
char last1,last2;
last1='a';last2='a';
ans=""; f=0;
for (i=0;i<n;i++)
{
if (s[i]<last1&&s[i]<last2){
cout<<"NO"<<endl;f=1;
break;
}
if (s[i]>=last1){
ans+='0';
last1=s[i];
}
else if (s[i]>=last2){
ans+='1';
last2=s[i];
}
}
if (f==0){
cout<<"YES"<<endl;
cout<<ans<<endl;
}
return 0;
}

浙公网安备 33010602011771号