https://www.luogu.org/problemnew/lists?name=&orderitem=difficulty&tag=2&content=0&select=1&type=
P1000 超级玛丽游戏
做过了,而且很无聊。
P2562 Kitty猫基因编码
又一个无聊题,题目的数据范围还错。
#includeusing namespace std; #define ll long long char s[261]; char ans[261]; int top; void check(int b,int l){ int all0=1,all1=1; for(int i=b;i){ if(s[i]=='0') all1=0; else all0=0; if(all1==0&&all0==0){ break; } } if(all0) ans[top++]='A'; else if(all1) ans[top++]='B'; else{ ans[top++]='C'; check(b,l/2); check(b+l/2,l/2); } //printf("%s\n",ans); } void solve(){ while(~scanf("%s",s)){ top=0; int n=strlen(s); check(0,n); ans[top++]='\0'; printf("%s\n",ans); } } int main(){ #ifdef Yinku freopen("Yinku.in","r",stdin); //freopen("Yinku.out","w",stdout); #endif // Yinku solve(); }
P2543 奇怪的字符串
模板的最长公共子序列会MLE,所以应该考虑更神奇的做法。
这个字符串明显只有0和1两种情况?
看了题解原来可以用滚动数组,从dp的方程可以推出来。
小心越界。(从1开始就没这么多破事)
#includeusing namespace std; #define ll long long char a[10005]; char b[10005]; int dp[2][10005]; int lcs(int al,int bl){ for(int i=0;i ){ for(int j=0;j ){ dp[i%2][j]=(a[i]==b[j])?(((i&&j)?dp[(i-1)%2][j-1]:0)+1):max(i?dp[(i-1)%2][j]:0,j?dp[i%2][j-1]:0); } } return dp[(al-1)%2][bl-1]; } void solve(){ while(~scanf("%s%s",a,b)){ memset(dp,0,sizeof(dp)); printf("%d\n",lcs(strlen(a),strlen(b))); } } int main(){ #ifdef Yinku freopen("Yinku.in","r",stdin); //freopen("Yinku.out","w",stdout); #endif // Yinku solve(); }
P3880 提示问题
注意fgets会连换行符一起保存在字符串中。
#includeusing namespace std; #define ll long long char s[105]; char ans1[105]; char ans2[105]; char ans3[105]; void solve(){ fgets(s,100,stdin); int l=strlen(s); ans1[l]=ans2[l]=ans3[l]='\0'; int cnt=0; for(int i=0;i ){ ans1[i]=s[i]; if(isalpha(s[i])){ ans1[i]='.'; cnt++; } } int show=round(1.0*cnt/3.0); for(int i=0;i ){ ans2[i]=ans1[i]; if(isalpha(s[i])&&show){ ans2[i]=s[i]; show--; } } int suc=0; for(int i=0;i ){ ans3[i]=ans2[i]; if(ans3[i]=='.'&&(s[i]=='A'||s[i]=='a'||s[i]=='E'||s[i]=='e'||s[i]=='I'||s[i]=='i'||s[i]=='O'||s[i]=='o'||s[i]=='U'||s[i]=='u')){ ans3[i]=s[i]; suc=1; } } if(suc==0){ show=round(cnt*2.0/3.0); for(int i=0;i ){ ans3[i]=ans1[i]; if(isalpha(s[i])&&show){ ans3[i]=s[i]; show--; } } } printf("%s%s%s",ans1,ans2,ans3); } int main(){ #ifdef Yinku //freopen("Yinku.in","r",stdin); //freopen("Yinku.out","w",stdout); #endif // Yinku solve(); }
P2771 建门 gates
这个跟字符串什么关系?这里造的是栅栏,不能直接存点,还要存点与点之间的边。直接广搜或者深搜都可以,记得记录xy的上下界加快过程。
#includeusing namespace std; #define ll long long int l; char s[1005]; int minx,maxx,miny,maxy; int g[4005][4005]; void bfs(int cnt,int bi,int bj){ queue int,int> >q; g[bi][bj]=cnt; q.push({bi,bj}); while(!q.empty()){ int i=q.front().first; int j=q.front().second; q.pop(); if(i>=minx&&g[i-1][j]==0){ q.push({i-1,j}); g[i-1][j]=cnt; } if(j>=miny&&g[i][j-1]==0){ q.push({i,j-1}); g[i][j-1]=cnt; } if(i<=maxx&&g[i+1][j]==0){ q.push({i+1,j}); g[i+1][j]=cnt; } if(j<=maxy&&g[i][j+1]==0){ q.push({i,j+1}); g[i][j+1]=cnt; } } } void solve(){ scanf("%d",&l); scanf("%s",&s); g[2001][2001]=-1; int curx=2001,cury=2001; minx=curx,maxx=curx,miny=cury,maxy=cury; for(int i=0;i ){ if(s[i]=='N'){ curx--; g[curx][cury]=-1; curx--; } else if(s[i]=='E'){ cury++; g[curx][cury]=-1; cury++; } else if(s[i]=='S'){ curx++; g[curx][cury]=-1; curx++; } else{ cury--; g[curx][cury]=-1; cury--; } g[curx][cury]=-1; minx=min(minx,curx); maxx=max(maxx,curx); miny=min(miny,cury); maxy=max(maxy,cury); } /*for(int i=1950;i<2050;i++){ for(int j=1950;j<2050;j++){ printf("%d",g[i][j]); } printf("\n"); } printf("----\n");*/ minx--; minx=max(0,minx); maxx++; miny--; miny=max(0,miny); maxy++; int cnt=0; for(int i=minx;i ){ for(int j=miny;j ){ if(g[i][j]==0){ //cout<<"i="<; bfs(cnt,i,j); } } } printf("%d\n",cnt-1); } int main(){ #ifdef Yinku freopen("Yinku.in","r",stdin); //freopen("Yinku.out","w",stdout); #endif // Yinku solve(); }
P3375 KMP字符串匹配
用kuangbin的KMP有什么问题呢?怎么就不一样呢?
#includeusing namespace std; #define ll long long char t[1000000]; char p[1000000]; int nex[1000000]; int pos[1000000]; void KMP_init(char p[],int pl,int nex[]){ int i=0,j=nex[0]=-1; while(i<pl){ while(j!=-1&&p[i]!=p[j])j=nex[j]; nex[++i]=++j; } } int KMP(char t[],char p[],int tl,int pl){ KMP_init(p,pl,nex); int i=0,j=0,ans=0; while(i<tl){ while(j!=-1&&t[i]!=p[j])j=nex[j]; i++,j++; if(j>=pl){ pos[ans++]=i-pl; j=nex[j]; } } return ans; } void solve(){ scanf("%s",&t); scanf("%s",&p); int tl=strlen(t); int pl=strlen(p); int top=KMP(t,p,tl,pl); for(int i=0;i ) printf("%d\n",pos[i]+1); for(int i=0;i ){ printf("%d%c",nex[i]," \n"[i==pl-1]); } } int main(){ #ifdef Yinku freopen("Yinku.in","r",stdin); //freopen("Yinku.out","w",stdout); #endif // Yinku solve(); }
P3612 Secret Cow Code秘密奶牛码
什么沙雕题啊……题都看不懂……经过题解的提示,每次把最后一个字符加到自己的最前面然后复制一整串。意思是说每次字符串被复制了一倍,设原长为 $l$(从1开始) 那么当 $n==l+1$ 时, $f(n)=(l)$。当 $n>=l+2$ 时, $f(n)=f(n-l-1)$,呃,这就是题解。每次先算出当前的一半 $l$ 就可以了。
打表用的代码:
#includeusing namespace std; #define ll long long char ans[35000]; int n; int top=0; void rot(){ //cout< int newtop=top; ans[top]=ans[top-1]; //cout< void solve(){ while(~scanf("%s",ans)){ cout<<endl; scanf("%d",&n); top=strlen(ans); for(int t=0;t<=6;t++){ rot(); } } } int main(){ #ifdef Yinku freopen("Yinku.in","r",stdin); //freopen("Yinku.out","w",stdout); #endif // Yinku solve(); }newtop++; for(int i=0;i ;i++){ ans[newtop++]=ans[i]; } top=newtop; ans[top]='\0'; cout<1 endl; }
AC代码:
#includeusing namespace std; #define ll long long char ans[35000]; ll n; void solve(){ while(~scanf("%s",ans)){ scanf("%lld",&n); int l=strlen(ans); while(n>l){ ll len=l; while(len*2 2; if(n==len+1) n=len; else n=n-len-1; } if(n<=l){ printf("%c\n",ans[n-1]); } } } int main(){ #ifdef Yinku freopen("Yinku.in","r",stdin); //freopen("Yinku.out","w",stdout); #endif // Yinku solve(); }
P3879 阅读理解
哈希可以过的就不用别的东西了,完全匹配嘛!
#includeusing namespace std; #define ll long long #define ull unsigned long long int t,p; set text[1005]; char s[25]; ull Hash(char s[]){ int l=strlen(s); ull H=0; for(int i=0;i ){ H=H*19260817+s[i]; } //cout< return H; } void solve(){ while(~scanf("%d",&t)){ for(int i=0;i int n; scanf("%d",&n); while(n--){ scanf("%s",s); //cout<){ //cout< text[i].insert(Hash(s)); } //cout<} scanf("%d",&p); while(p--){ scanf("%s",s); //cout< //cout< ull H=Hash(s); int fi=1; for(int i=0;iif(text[i].count(H)){ if(fi) printf("%d",i+1),fi=0; else printf(" %d",i+1); } } printf("\n"); } } } int main(){ #ifdef Yinku freopen("Yinku.in","r",stdin); //freopen("Yinku.out","w",stdout); #endif // Yinku solve(); }){
上面的都是一直到提高组的难度,感觉还ok吧……
P2814 家谱
岂不是一个父指针树就可以了?还保证树高不超过30,这比前面的题还水吧?
我还哈希半天,汗,直接一个map搞定。
#includeusing namespace std; #define ll long long #define ull unsigned long long map<string,string> p; map<string,int> havep; string s; string t; char ins; void solve(){ while(~scanf(" %c",&ins)){ cin>>s; if(ins=='$') break; if(ins=='#'){ t=s; } else if(ins=='+'){ p[s]=t; havep[s]=1; } else{ t=s; while(havep[s])s=p[s]; cout< " "< endl; } } } int main(){ #ifdef Yinku freopen("Yinku.in","r",stdin); //freopen("Yinku.out","w",stdout); #endif // Yinku solve(); }
P3808 AC自动机(简单版)
我其实是先做的加强版……这里简单版的话,防止同一个模式串被统计多次就要清空它了。模板交上去居然TLE了,先仔细想想。
我懂了,其实是因为我们先在只考虑某个模式串是不是出现过,那么被搜索过的可以标为-1然后下一次搜索到的时候跳过。但是这是为什么呢?这其实很好想,你从文本串中进入到这个节点,就说明文本串中有对应的串,假如他是模式串就顺手统计了,不然就证明这个串以后都没有啥用了(每次向它的前缀转移)。
#includeusing namespace std; #define ll long long struct Trie{ int nex[1000010][26],fail[1000010],End[1000010]; int root,L; int newnode(){ /*for(int i=0;i<26;i++) nex[L][i]=-1;*/ End[L++]=0; return L-1; } int cnt; void init(){ L=0; cnt=0; memset(nex,-1,sizeof(nex)); root=newnode(); } void insert(char buf[]){ int len=strlen(buf); int now=root; for(int i=0;i ){ int &t=nex[now][buf[i]-'a']; if(t==-1) t=newnode(); now=t; } End[now]++; cnt++; } void build(){ queue<int>Q; fail[root]=root; for(int i=0;i<26;i++){ if(nex[root][i]==-1) nex[root][i]=root; else{ fail[nex[root][i]]=root; Q.push(nex[root][i]); } } while(!Q.empty()){ int now=Q.front(); Q.pop(); for(int i=0;i<26;i++) if(nex[now][i]==-1) nex[now][i]=nex[fail[now]][i]; else{ fail[nex[now][i]]=nex[fail[now]][i]; Q.push(nex[now][i]); } } } int query(char buf[]){ int len=strlen(buf); int now=root; int res=0; for(int i=0;i ){ now=nex[now][buf[i]-'a']; int temp=now; while(temp!=root&&End[temp]!=-1){ res+=End[temp]; End[temp]=-1; temp=fail[temp]; } //if(res==cnt) //return res; } return res; } }; char buf[1000010]; Trie ac; int n; void solve(){ while(~scanf("%d",&n)){ if(n==0) break; ac.init(); for(int i=0;i ){ scanf("%s",buf); ac.insert(buf); } ac.build(); scanf("%s",buf); cout< endl; } } int main(){ #ifdef Yinku freopen("Yinku.in","r",stdin); //freopen("Yinku.out","w",stdout); #endif // Yinku solve(); }
P3796 AC自动机(加强版)
第一次做AC自动机,丑了一点。这个是要计数所以不能够像上面那样搜索到了就破坏掉自动机。记得在计数的时候,要先去掉End[temp]=0防止被清空,然后用cnt[temp]就可以统计该模式串匹配的次数,然后用i2s[temp]记录出需要的string,最后弄个s2i保存string的输入顺序。弄得超级复杂。
#includeusing namespace std; #define ll long long struct sid{ string s; int id; bool operator<(sid i){ return id<i.id; } }sid2[200]; map<string,int> s2i; map<int,string> i2s; struct Trie{ int nex[500010][26],fail[500010],End[500010]; int root,L; int newnode(){ for(int i=0;i<26;i++) nex[L][i]=-1; End[L++]=0; return L-1; } void init(){ L=0; memset(cnt,0,sizeof(cnt)); maxcnt=0; root=newnode(); } void insert(char buf[]){ int len=strlen(buf); int now=root; for(int i=0;i ){ if(nex[now][buf[i]-'a']==-1) nex[now][buf[i]-'a']=newnode(); now=nex[now][buf[i]-'a']; } End[now]++; i2s[now]=string(buf); } void build(){ queue<int>Q; fail[root]=root; for(int i=0;i<26;i++){ if(nex[root][i]==-1) nex[root][i]=root; else{ fail[nex[root][i]]=root; Q.push(nex[root][i]); } } while(!Q.empty()){ int now=Q.front(); Q.pop(); for(int i=0;i<26;i++) if(nex[now][i]==-1) nex[now][i]=nex[fail[now]][i]; else{ fail[nex[now][i]]=nex[fail[now]][i]; Q.push(nex[now][i]); } } } int cnt[500010],maxcnt; vector<int> A; int query(char buf[]){ int len=strlen(buf); int now=root; int res=0; for(int i=0;i ){ now=nex[now][buf[i]-'a']; int temp=now; while(temp!=root){ res+=End[temp]; //End[temp]=0; cnt[temp]+=End[temp]; if(cnt[temp]>maxcnt){ A.clear(); maxcnt=cnt[temp]; A.push_back(temp); } else if(cnt[temp]==maxcnt){ A.push_back(temp); } temp=fail[temp]; } } return res; } }; char buf[1000010]; Trie ac; int n; void solve(){ while(~scanf("%d",&n)){ if(n==0) break; ac.init(); i2s.clear(); s2i.clear(); for(int i=0;i ){ scanf("%s",buf); ac.insert(buf); string tmp(buf); //sid2[i].s=tmp; //sid2[i].id=i; s2i[tmp]=i; } ac.build(); scanf("%s",buf); ac.query(buf); cout< endl; vector v; for(auto i:ac.A){ sid t; t.s=i2s[i]; t.id=s2i[t.s]; v.push_back(t); } sort(v.begin(),v.end()); for(auto i:v){ cout< endl; } } } int main(){ #ifdef Yinku freopen("Yinku.in","r",stdin); //freopen("Yinku.out","w",stdout); #endif // Yinku solve(); }