7/24 第四次多校
1001_hdu5763
听说有人没用kmp直接平方过了(摔)
/*令dp[i]表示到i结尾的字符串可以表示的不同含义数,那么考虑两种转移:
末尾不替换含义:dp[i - 1]
末尾替换含义:dp[i - |B|] (A.substr(i - |B| + 1,|B|) = B)
那么对于末尾替换含义的转移,需要快速判断BB能不能和当前位置的后缀匹配,kmp或者hash判断即可。
复杂度:O(N)*/
//cww97
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=100007;
const int P=1000000007;
char a[N],b[N];
bool mat[N];
int next[N];
ll f[N];
void getNext(int m){
int i=0,j=-1;
next[0]=-1;
while (i<m){
if (j==-1||b[i]==b[j]){
if (b[++i]!=b[++j])next[i]=j;
else next[i]=next[j];
}else j=next[j];
}
}
void KMP(int n,int m){
memset(mat,0,sizeof(mat));
int i=0,j=0;
getNext(m);
while (i<n&&j<m){
if (j==-1||a[i]==b[j])i++,j++;
else j=next[j];
if (!i&&!j)break;
if (j==m){
mat[i]=1;
//printf("mat[%d]get\n",i);
j=next[j];
}
}
}
int main(){
//freopen("fuck.in","r",stdin);
int T;
scanf("%d\n",&T);
for (int cas=1;cas<=T;cas++){
scanf("%s%s",a,b);
int n=strlen(a);
int m=strlen(b);
KMP(n,m);
memset(f,0,sizeof(f));
f[0]=1;
for (int i=1;i<=n+1;i++){
if (mat[i])f[i]=(f[i-m]+f[i-1])%P;
else f[i]=(f[i-1])%P;
//printf("f[%d]=%d\n",i,f[i]);
}
printf("Case #%d: %I64d\n",cas,f[n]%P);
}
return 0;
}
1010_hdu5773
复制下cw的讲解:
很巧妙的智商题。意思是数列里的 0 可以替换成任何数。做法很巧妙,如果 a1 ai 中有 z 个 0 的话,就把 ai 当作 ai − z 处理。遇到 0 不处理,最后把答案数加上总的 0 的个数即可
#include<cstdio>
using namespace std;
const int N=1000010;
int s[N],top,num;
int Find(int x){
int l=1,r=top;
while (l<r){
int mid=(l+r)>>1;
if (s[mid]<=x)l=mid+1;
else r=mid;
}
return l;
}
int main(){
int T,n,x;
scanf("%d",&T);
for (int cas=1;cas<=T;cas++){
scanf("%d",&n);
num=0,top=0;
s[0]=-100000007;
for (;n--;){
scanf("%d",&x);
if (!x)num++;
else {
x-=num;
if (x>s[top]) s[++top]=x;
else s[Find(x)]=x;
}
}
printf("Case #%d: %d\n",cas,top+num);
}
return 0;
}
1011
第一次见吧
#include<cstdio>
#include<map>
#include<string>
#include<iostream>
using namespace std;
map<string,int>mp;
int a[100];
int main(){
//freopen("fuck.in","r",stdin);
mp["Cleveland Cavaliers"]=0; a[0]=1;
mp["San Antonio Spurs"]=1; a[1]=5;
mp["Miami Heat"]=2; a[2]=3;
mp["Dallas Mavericks"]=3; a[3]=1;
mp["L.A. Lakers"]=4; a[4]=11;
mp["Boston Celtics"]=5; a[5]=17;
mp["Detroit Pistons"]=7; a[7]=3;
mp["Chicago Bulls"]=8; a[8]=6;
mp["Houston Rockets"]=9; a[9]=2;
mp["Philadelphia 76ers"]=10; a[10]=2;
mp["Seattle Sonics"]=11; a[11]=1;
mp["Washington Bullets"]=12; a[12]=1;
mp["Portland Trail Blazers"]=13;a[13]=1;
mp["Golden State Warriors"]=14;a[14]=2;
mp["New York Knicks"]=15; a[15]=2;
mp["Milwaukee Bucks"]=16; a[16]=1;
mp["St. Louis Hawks"]=17; a[17]=1;
mp["Philadelphia Warriors"]=18;a[18]=2;
mp["Syracuse Nats"]=19; a[19]=1;
mp["Minneapolis Lakers"]=20; a[20]=5;
mp["Rochester Royals"]=21; a[21]=1;
mp["Baltimore Bullets"]=22; a[22]=1;
int T,ans;
string st;
scanf("%d\n",&T);
for (int cas=1;cas<=T;cas++){
getline(cin,st);
if (mp.find(st)==mp.end())ans=0;
else ans=a[mp[st]];
printf("Case #%d: %d\n",cas,ans);
}
return 0;
}
1012
一开始跟队友同时交了一发abs(a[i]-i),,,T_T
树状数组维护逆序对
cw的讲解:
问在冒泡排序中,每个数可能出现的最左位置和最右位置之差。最多往右移动次数其实就是这个数在当前位置时右边有多少个比它小的个数,这个倒过来做一遍即可,用树状数组维护。接着再排序一遍,在初始位置,最右位置,排序后的位置中分别找出最左和最右,然后算出答案。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
int a[N],c[N],l[N],r[N];
int n;
int sum(int x){
int s=0;
for (;x;x-=x&-x) s+=c[x];
return s;
}
void add(int x){
for (;x<=n;x+=x&-x) c[x]++;
}
int main(){
//freopen("fuck.in","r",stdin);
int T,x;
scanf("%d",&T);
for (int cas=1;cas<=T;cas++){
memset(c,0,sizeof(c));
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
l[a[i]]=i;
}
for (int i=n;i;i--){
r[a[i]]=l[a[i]]+sum(a[i]-1);
add(a[i]);
l[a[i]]=min(a[i],i);
//printf("%d,l=%d,r=%d\n",a[i],l[a[i]],r[a[i]]);
}
printf("Case #%d:",cas);
for (int i=1;i<=n;i++) {
printf(" %d",r[i]-l[i]);
}
puts("");
}
return 0;
}