第一题
//第一次和二中联考,深深的感觉到了自己的不足
题面:1.
diyiti.cpp/c/pas diyiti.in diyiti.out 2s/256MB
给定两个01串,S,T(下标从0开始)。
支持如下3种操作:
修改S第i位的字符,即0->1,1->0.
修改T第i位的字符,即0->1,1->0.
查询S[a..a+l-1],T[b..b+l-1]的相似度。
相似度定义如下:
s,t两个字符串的相似度=sigma_{i=0}^{|s|-1} sim(s[i],t[i])
sim(a,b) 有四个参数p_{0,0},p_{0,1},p_{1,0},p_{1,1}。 sim(a,b)的返回值为p_{a,b}。
input
第一行一个非空字符串S
第二行一个非空字符串T
第三行一个操作个数Q
接下来Q行,每行为”1 i”,”2 i”或”3 a b l p_{0,0} p_{0,1} p_{1,0} p_{1,1}”
output
若干行,每行对应每个3操作的答案。
sample in
1010 0101 6 3 0 0 4 1 2 3 4 1 1 3 0 1 3 4 3 7 6 2 2 3 1 0 2 4 5 3 4 3
1 0 3 8 8 8 8sample out
10 19 7 24
10%, |S|,|T|<=1000,Q<=1000 10%, |S|,|T|<=50000,Q<=50000,3操作的p值都为1 10%,
|S|,|T|<=50000,Q<=50000,所有操作为3操作且a,b,l相同 20%,
|S|,|T|<=50000,Q<=50000,3操作的a,b值为0 50%,
|S|,|T|<=100000,Q<=100000,0<=p<=50,由于数据随机生成,可以默认3操作l的期望为|S|/6
这道题气死我了!!!!!
我是这么认为的,暴力+特判20,加线段树50分,正解想不出来然后……
暴力50分
暴力加快读80分
暴力加快快读就过了
1.线段树呢大概是这样做的
把每一种情况的数量作为线段树储存的东西然后就是线段树的储存和修改和出解,因为昨天晚上没睡好,调试了巨久,本来以为至少能拉开一点分差结果……
上代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
char s[maxn],t[maxn];
int tree[5][maxn],a[maxn];
int f[2][2];
void build(int l,int r,int rt)
{
if (l==r)
{
tree[a[l]][rt]++;
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
for (int i=1; i<=4; i++)
tree[i][rt]=tree[i][rt<<1]+tree[i][rt<<1|1];
}
void add(int L,int l,int r,int rt,int kind)
{
if (l==r)
{
tree[kind][rt]--;
return;
}
int mid=(l+r)>>1;
if (L<=mid)
add(L,l,mid,rt<<1,kind);
else
add(L,mid+1,r,rt<<1|1,kind);
tree[kind][rt]=tree[kind][rt<<1]+tree[kind][rt<<1|1];
}
void add1(int L,int l,int r,int rt,int kind)
{
if (l==r)
{
tree[kind][rt]++;
return;
}
int mid=(l+r)>>1;
if (L<=mid)
add(L,l,mid,rt<<1,kind);
else
add(L,mid+1,r,rt<<1|1,kind);
tree[kind][rt]=tree[kind][rt<<1]+tree[kind][rt<<1|1];
}
long long query(int L,int R,int l,int r,int rt,int kind)
{
if (L<=l&&r<=R)
return tree[kind][rt];
int mid=(l+r)>>1;
long long ANS=0;
if (L<=mid) ANS+=query(L,R,l,mid,rt<<1,kind);
if (R>mid) ANS+=query(L,R,mid+1,r,rt<<1|1,kind);
return ANS;
}
int main()
{
freopen("diyiti.in","r",stdin);
freopen("diyiti.out","w",stdout);
scanf("%s",s);
scanf("%s",t);
int ls=strlen(s),lt=strlen(t),ll=min(lt,ls)-1;
f[0][0]=1;
f[0][1]=2;
f[1][0]=3;
f[1][1]=4;
for (int i=0; i<=ll; i++)
a[i]=f[s[i]-48][t[i]-48];
build(0,ll,0);
int q;
scanf("%d",&q);
if (ll>1000)
while (q--)
{
int x;
scanf("%d",&x);
if (x==1)
{
int y;
scanf("%d",&y);
add(y,0,ll,0,a[y]);
if (s[y]=='0') s[y]='1';
else
if (s[y]=='1') s[y]='0';
a[y]=f[s[y]-48][t[y]-48];
add1(y,0,ll,0,a[y]);
}
if (x==2)
{
int y;
scanf("%d",&y);
add(y,0,ll,0,a[y]);
if (t[y]=='0') t[y]='1';
else
if (t[y]=='1') t[y]='0';
a[y]=f[s[y]-48][t[y]-48];
add1(y,0,ll,0,a[y]);
}
if (x==3)
{
int la,lb,lll;
scanf("%d%d%d",&la,&lb,&lll);
int p[5];
scanf("%d%d%d%d",&p[1],&p[2],&p[3],&p[4]);
if (p[1]==1&&p[2]==1&&p[3]==1&&p[4]==1)
{
cout<<lll<<"\n";
}
else {
long long ans=0;
for (int i=1; i<=4; i++)
ans+=query(la,la+lll,0,ll,0,i)*p[i];
printf("%lld\n",ans);
}
}
}
if (ll<=1000)
while (q--)
{
int x;
scanf("%d",&x);
if (x==1)
{
int y;
scanf("%d",&y);
if (s[y]=='0') s[y]='1'; else s[y]='0';
}
if (x==2)
{
int y;
scanf("%d",&y);
if (t[y]=='0') t[y]='1'; else t[y]='0';
}
if (x==3)
{
int la,lb,lll;
scanf("%d%d%d",&la,&lb,&lll);
int p[5];
scanf("%d%d%d%d",&p[1],&p[2],&p[3],&p[4]);
long long ans=0;
for (int i=la,j=lb; i<=la+lll-1; i++,j++)
ans+=p[f[s[i]-48][t[j]-48]];
cout<<ans<<"\n";
}
}
}
注意:线段树只能储存同位比对的情况!!!
2.暴力加快读,真的对于这种写法很气愤!!!
上代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define interesting int
namespace My_IO{inline char read(){
// return getchar();
static const int IN_LEN=1000000;static char buf[IN_LEN],*s,*t;
if(s==t){ t=(s=buf)+fread(buf,1,IN_LEN,stdin); if(s==t) return -1;}return*s++;
} template<class T>inline void rd(T&x){static bool iosig;static char c;
for(iosig=false,c=read();!isdigit(c);c=read()){if(c=='-') iosig=true; if(c==-1) return;}
for(x=0;isdigit(c);c=read())x=(x+(x<<2)<<1)+(c^'0');if(iosig) x=-x;
} const int OUT_LEN=10000000;char obuf[OUT_LEN],*ooh=obuf;
inline void print(char c){if(ooh==obuf+OUT_LEN) fwrite(obuf,1,OUT_LEN,stdout),ooh=obuf;*ooh++ = c;}
template<class T>inline void print(T x){static int buf[30],cnt;if (x == 0) print('0');
else {if(x<0) print('-'),x=-x;for(cnt=0;x;x/=10) buf[++cnt]=x%10+48;while(cnt) print((char)buf[cnt--]);}
} inline void flush(){fwrite(obuf, 1, ooh - obuf, stdout);}
}using namespace My_IO;
const int N=1E5+10;
int la,lb,T;
char a[N],b[N];
int main()
{
freopen("diyiti.in","r",stdin);
freopen("diyiti.out","w",stdout);
scanf("%s%s",a,b);
la=strlen(a);
lb=strlen(b);
for(int i=0;i<la;i++) a[i]-='0';
for(int i=0;i<lb;i++) b[i]-='0';
rd(T);
int od,x,ba,bb,l,f[2][2],ans;
while(T--){
rd(od);
if(od==1){
rd(x);
a[x]^=1;
}else if(od==2){
rd(x);
b[x]^=1;
}else{
ans=0;
rd(ba);rd(bb);rd(l);
rd(f[0][0]);rd(f[0][1]);
rd(f[1][0]);rd(f[1][1]);
for(int i=0;i<l;i++){
ans+=f[a[ba+i]][b[bb+i]];
}
printf("%d\n",ans);
}
}
return 0;
}
这个快读实在是太可恶了
3.还有第三种非常玄妙的位运算,讲道理我不懂,但是先上代码
大概是每二十位压位,然后位运算xor来比对,具体怎么比对我……
这种方法的可行性是位运算比普通比对快太多了
#include<cstdio>
#include<algorithm>
#include<ctype.h>
#include<string.h>
#include<math.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define travel(i,x) for(int i=h[x];i;i=pre[i])
inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
return (s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin), (s == t ? -1 : *s++) : *s++);
}
template<class T>
inline void read(T &x) {
static bool iosig;
static char c;
for (iosig = false, c = read(); !isdigit(c); c = read()) {
if (c == '-') iosig = true;
if (c == -1) return;
}
for (x = 0; isdigit(c); c = read()) x = ((x + (x << 2)) << 1) + (c ^ '0');
if (iosig) x = -x;
}
const int OUT_LEN = 10000000;
char obuf[OUT_LEN], *ooh = obuf;
inline void print(char c) {
if (ooh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), ooh = obuf;
*ooh++ = c;
}
template<class T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) print('0');
else {
if (x < 0) print('-'), x = -x;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
while (cnt) print((char)buf[cnt--]);
}
}
inline void flush() { fwrite(obuf, 1, ooh - obuf, stdout); }
const int N = 100005, M = N/64+5;
int n, m, mx, q, pcnt[1<<16], tt[N], ts[N];
char s[N], t[N];
ull a[M], b[64][M];
inline int cnt1(ull x, int l, int r){
int cnt=0;
rep(i, l, r) cnt+=(x>>i)&1;
return cnt;
}
inline int cnt2(ull x){ return pcnt[x&65535]+pcnt[x>>16&65535]+pcnt[x>>32&65535]+pcnt[x>>48];}
inline int calc(int x, int y, int l){
if(l<=100){
int tot=0;
rep(i, 0, l-1) tot+=s[i+x]&t[i+y];
return tot;
}
int tmp=(y-x+1048576)&63;
int tot=cnt1(a[y>>6]&b[tmp][(x+tmp)>>6], y&63, 63);
l-=64-(y&63);
y>>=6, x=(x+tmp)>>6;
for(; ++x, ++y, l>=64; l-=64) tot+=cnt2(a[y]&b[tmp][x]);
tot+=cnt1(a[y]&b[tmp][x], 0, l-1);
return tot;
}
inline void modify(int *tt, int x, int val){ ++x; while(x<=mx) tt[x]+=val, x+=x&-x;}
inline int query(int *tt, int x){ ++x; int ass=0; while(x) ass+=tt[x], x^=x&-x; return ass;}
int main() {
freopen("diyiti.in", "r", stdin);
freopen("diyiti.out", "w", stdout);
rep(i, 1, 65535) pcnt[i]=pcnt[i^(i&-i)]+1;
while(isspace(s[0]=read()));
while(isdigit(s[++n]=read()));
while(isspace(t[0]=read()));
while(isdigit(t[++m]=read()));
mx=max(m, n);
rep(i, 0, m-1) if(t[i]^='0') a[i>>6]|=(1ull<<(i&63)), modify(tt, i, 1);
rep(i, 0, n-1) if(s[i]^='0') modify(ts, i, 1);
rep(i, 0, 63) rep(j, 0, n-1) if(s[j]){
int id=i+j;
b[i][id>>6]|=(1ull<<(id&63));
}
read(q);
while(q--){
static int opt, x, y, l, p0, p1, p2, p3;
read(opt), read(x);
if(opt==2){
a[x>>6]^=(1ull<<(x&63));
if(t[x]^=1) modify(tt, x, 1); else modify(tt, x, -1);
}
else if(opt==1){
rep(i, 0, 63) b[i][(x+i)>>6]^=(1ull<<((x+i)&63));
if(s[x]^=1) modify(ts, x, 1); else modify(ts, x, -1);
}
else{
read(y), read(l), read(p0), read(p1), read(p2), read(p3);
print(l*p0+(query(tt, y+l-1)-query(tt, y-1))*(p1-p0)+(query(ts, x+l-1)-query(ts, x-1))*(p2-p0)+calc(x, y, l)*(p3-p2-p1+p0)), print('\n');
// printf("%d\n", calc(x, y, l));
}
}
return flush(), 0;
}