Description Sample Input
Sample Output
|
题意:给你一个长度小于等于10^6的字符串,然后每次让它循环铺盖,构成层数为n的塔,让你求得第i层塔中某个字符的个数。
思路:首先要注意到字符串是从左到右覆盖该行和从右到做覆盖该行不影响结果,所以我们全部考虑为从左到右覆盖。我们先遍历一遍字符串,用vector<int>vect[30]记录字符为i的所有位置。然后我们看c是不是能被字符串的长度len整除,如果能,那么答案就是vec[c-'A'+1].size()*c/len,如果不能整除,那么我们就要把余下的部分算完。当我们把中间的整段字符串都去掉的时候,余下的部分可能是前面一串,或者后面一串,或者前面后面都有剩下的,这里一开始我直接算前一串的开头到len-1中的数量加上后一串的0到结尾的数量,但是wa了,因为这样的想法是错误的。因为我这样算可能会包含已经算过的,比如abcdefabcdef,如果我选第2个b和倒数第2个e,那么我这样算的话,会包含之前算过的,因为两个字符间的距离大于len了。所以我们要采用别的方法,起始点q固定,尾节点变为(q+(c%len))%len,那么起始点和尾节点之间的距离一定小于len了,这样就不会重复算了。
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<bitset> #include<algorithm> using namespace std; typedef long long ll; typedef long double ldb; #define inf 99999999 #define pi acos(-1.0) #define maxn 1000050 vector<int>vec[30]; vector<int>::iterator it; int len; int chuli(int pos,int bianhao) { int i,j; int p; p=upper_bound(vec[bianhao].begin(),vec[bianhao].end(),pos)-vec[bianhao].begin(); return p; } int getkaitou(ll ceng) { int i,j; ll sum; if(ceng==1)return 0; if(ceng%2==0)sum=( (ceng/2%len)*((ceng-1)%len)+1 )%len; else sum=( (ceng%len)*((ceng-1)/2%len)+1 )%len; if(sum==0)sum=len-1; else sum--; return sum; } char s[maxn]; int main() { int m,i,j; ll n,c; while(scanf("%lld",&n)!=EOF) { scanf("%s",s); len=strlen(s); for(i=1;i<=26;i++)vec[i].clear(); for(i=0;i<len;i++){ vec[s[i]-'A'+1].push_back(i); } char str[10]; int p; ll sum; scanf("%d",&m); while(m--){ scanf("%lld%s",&c,str); int bianhao=str[0]-'A'+1; int kaitou=getkaitou(c); if(c%len==0){ printf("%lld\n",(ll)vec[bianhao].size()*(ll)(c/len) ); continue; } ll beishu=c/len; sum=0; sum+=(ll)beishu*(ll)vec[bianhao].size(); ll jianju=c%len; int jiewei=(kaitou+jianju-1)%len; if(kaitou<=jiewei){ printf("%lld\n",sum+chuli(jiewei,bianhao)-chuli(kaitou-1,bianhao) ); } else{ printf("%lld\n",sum+chuli(jiewei,bianhao)+chuli(len-1,bianhao)-chuli(kaitou-1,bianhao) ); } } } return 0; }