Contest:https://ac.nowcoder.com/acm/contest/1083#question
当时comet和这个重了,就去打comet了(谁让comet奖品看起来更好一点呢),结果被吊打,最后一个小时才来写这场,想着混个签到抽抽短袖,结果发现题目意外的简单点?(结果成了二分场?是不是数据很水啊....)
题目链接:https://ac.nowcoder.com/acm/contest/1083/A
题目大意:给出一个只含小写字母的字符串S,找出S的子序列abc的个数。
思路:遍历a,二分每个a后面的第一个b,再找出c,随便过。。。
ACCode:
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
char S[MAXN];
int A[MAXN],B[MAXN],C[MAXN];
int tota,totb,totc;
int main(){
scanf("%s",S+1);
int len=strlen(S+1);
tota=totb=totc=0;
for(int i=1;i<=len;++i){
if(S[i]=='a') A[++tota]=i;
else if(S[i]=='b') B[++totb]=i;
else if(S[i]=='c') C[++totc]=i;
}
ll ans=0;
for(int i=1;i<=tota;++i){
int l=1,r=totb,mid;
while(l<=r){//找到第一个B[mid]>=A[i]
mid=(l+r)>>1;
if(B[mid]<=A[i]) l=mid+1;
else r=mid-1;
}
int posb=l;
if(posb>totb) continue;
for(int j=posb;j<=totb;++j){
l=1,r=totc;
while(l<=r){
mid=(l+r)>>1;
if(C[mid]<=B[j]) l=mid+1;
else r=mid-1;
}
int posc=l;
if(posc>totc) break;
ans+=totc-posc+1;
}
}printf("%lld\n",ans);
}
题目链接:https://ac.nowcoder.com/acm/contest/1083/B
题目大意:给出一个字符串S,对于q次询问,每次给出字符串p,判断p是不是S的子序列
思路:对于p[i],肯定是找第一个出现在S中的字符,所以二分就好了,随便过。。
ACCode:
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
char S[MAXN],P[MAXN];
int Pos[30][MAXN],Totx[30],Idx[30];
int n,q;
int main(){
scanf("%d%d",&n,&q);
scanf("%s",S+1);
for(int i=1;i<=n;++i){
int ch=S[i]-'a'+1;
Pos[ch][++Totx[ch]]=i;
}
while(q--){
scanf("%s",P+1);int len=strlen(P+1);
for(int i=0;i<30;++i) Idx[i]=0;
int flag=1,l,r,mid,pre=Pos[P[1]-'a'+1][1];
for(int i=2;i<=len;++i){
int ch=P[i]-'a'+1;
l=1,r=Totx[ch];
while(l<=r){
mid=(l+r)>>1;
if(Pos[ch][mid]<=pre) l=mid+1;
else r=mid-1;
}
if(l>Totx[ch]){
flag=0;break;
}pre=Pos[ch][l];
}
if(flag) printf("YES\n");
else printf("NO\n");
}
}
题目链接:https://ac.nowcoder.com/acm/contest/1083/C
题目大意:给出一个长度l,判断该长度是否是直角三角形的一边,边都只能是整数。输出另外两边。
思路:之前碰到过这道题,一个结论题,问了问队友,结果数论队友直接秒掉了。。
ACCode:
int main(){
ll a,b;
cin>>a>>b;
int flag=0;
if(a%2&&a>1){
ll n=(a-1)/2;
cout<<2*n*n+2*n<<" "<<2*n*n+2*n+1<=4){
ll n=a/2;
cout<
题目链接:https://ac.nowcoder.com/acm/contest/1083/D
题目大意:中文题
思路:想着先写一个q*400的匈牙利,T了再说。。结果就过了。。
队友完全暴力,q*(r-l+1)*n的查询。。都过了。。
ACCode:
const int MAXN=1e3+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
struct Edge1{
int v,val,nxt;
Edge1(int _v=0,int _val=0,int _nxt=0){
v=_v;val=_val;nxt=_nxt;
}
};
Edge1 Edge[MAXN*MAXN];
int Head[MAXN],Ecnt;
int L[MAXN],R[MAXN];
int Flag[MAXN],Vis[MAXN];
int ql,qr;
int n,q;
void Intt(){
clean(Head,-1);Ecnt=0;
}
void AddEdge(int u,int v,int val){
Edge[Ecnt]=Edge1(v,val,Head[u]);
Head[u]=Ecnt++;
}
int DFS(int u){
for(int i=Head[u];i+1;i=Edge[i].nxt){
int v=Edge[i].v;//对应编号的羊
if(Vis[v]==0){
Vis[v]=1;
if(Flag[v]==0||DFS(Flag[v])){
Flag[v]=u;
return 1;
}
}
}return 0;
}
int main(){
scanf("%d%d",&n,&q);
Intt();
for(int i=1;i<=n;++i) scanf("%d",&L[i]);
for(int i=1;i<=n;++i) scanf("%d",&R[i]);
for(int i=1;i<=n;++i){
for(int j=L[i];j<=R[i];++j){
AddEdge(i,400+j,1);AddEdge(400+j,i,0);
}
}
while(q--){
scanf("%d%d",&ql,&qr);
ql+=400;qr+=400;
clean(Vis,0);clean(Flag,0);
int ans=0;
for(int i=ql;i<=qr;++i){
clean(Vis,0);
if(DFS(i)) ans++;
}printf("%d\n",ans);
}
}
题目链接:https://ac.nowcoder.com/acm/contest/1083/E
题目大意:中文题
思路:一开始没什么思路,想着贪心,但一直模拟不出贪心策略,后来听见队友来了句二分。。woc!可以二分连续的区间数量,利用贪心思想,尽量平摊区间长度,多余的加前后都行。结果就二分出来了。。。
ans=n-(不连续区间数量),找出最小的不连续递增区间数量就好了。
ACCode:
const int MAXN=1e3+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
int n,m;
int Judge(int mid){
int len=n/mid,del=n%mid;//每段len个元素,剩下del个元素分到前面
int Sum=del*(1+len+1)*(len+1)/2+(mid-del)*(1+len)*len/2;
return Sum;//花费
}
int main(){
scanf("%d%d",&n,&m);
int l=1,r=n,mid;
while(l<=r){//找到第一个符合要求的mid
mid=(l+r)>>1;
if(Judge(mid)<=m) r=mid-1;//符合要求
else l=mid+1;
}
int len=n/l,del=n%l;
for(int i=1;i<=l;++i){
if(del){
for(int j=1;j<=len+1;++j) printf("%d ",j);
--del;
}
else{
for(int j=1;j<=len;++j) printf("%d ",j);
}
}
}
题目链接:https://ac.nowcoder.com/acm/contest/1083/F
题目大意:中文题
思路:有点类似上星期的南昌C?据说也是抄的CF Goodbye2017E。。
用矩阵维护子序列的数量,加个LCA,用树剖维护子序列。注意一下线段树合并。
但是还是没思路(因为这两道都没有写出来QAQ)
赛后看的题解。
https://ac.nowcoder.com/discuss/248083?type=101&order=0&pos=19&page=0
需要注意的是,查询的字符串是v->u的顺序,所以两个链所合并的顺序是不一样的。
但听队友说有一个主席树的解法,常数更小。抽空再看看把QAQ
ACCode:
#include
#include
#include
#include
#include
// srand((unsigned)time(NULL));rand();
#include