acm萌新,以后在这个博客更新和记录一些题目吧
本来以为这场div3能上分,结果t3卡住了,然后t4明明很简单但只扫了一眼......
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 ",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; }