先写一下总结
突然有兴致去打CF…以前好像就打过一次,那次还没认真打…
英语能力有待提升,16分钟敲完前两题你猜我时间花在哪了?
明明C题离正解只有一步之遥了,但就是没想到可以划分出各个区间…智商捉急啊QAQ
D题的kmp明明考场上就get正解了,最后竟然败在了变量名和longlong上!为什么对拍没拍出错!以后还是先静态查错吧QAQ
E题只能说看懂题了,不太会搞的样子…
总之以后需要:积累考试经验,找到考试感觉,打完代码先用脑子检查一遍,思维题要大胆去想(cai)。CF只有俩小时确实时间也不太够…
虽然没我想象的那么好,不过好歹说是涨rating了,就这样吧。
SB题
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int SZ = 1000010;
int a[SZ],b[SZ];
int main()
{
int n;
scanf("%d",&n);
int ans1 = 0,ans2 = 0;
for(int i = 1;i <= n;i ++)
{
scanf("%d",&a[i]);
ans1 |= a[i];
}
for(int i = 1;i <= n;i ++)
{
scanf("%d",&b[i]);
ans2 |= b[i];
}
printf("%d\n",ans1 + ans2);
return 0;
}
SB题
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int SZ = 1000010;
struct haha{
int id,x;
}r[SZ],c[SZ];
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i = 1;i <= k;i ++)
{
int k,x,a;
scanf("%d%d%d",&k,&x,&a);
if(k == 1)
r[x] = (haha){i,a};
else
c[x] = (haha){i,a};
}
for(int i = 1;i <= n;i ++)
{
for(int j = 1;j <= m;j ++)
{
if(r[i].id == 0 && c[j].id == 0) printf("0 ");
else if(r[i].id > c[j].id) printf("%d ",r[i].x);
else printf("%d ",c[j].x);
}
puts("");
}
return 0;
}
给一个序列,m次操作,每次形如:把[1,ri]按升序/降序排列。求最终序列。
容易发现,若存在一个 ri>rj,i>j 则j操作是无用的,所以可以先用单调栈维护一个ri单减的操作序列,只有这些操作有用。
然后把新的操作放到一个操作序列里,满足 ri>ri+1 。
然后对于每个区间 [ri+1+1,ri] ,只有第i次操作对它有贡献。若第i次操作是升序,则 ri=max1,ri−1=max2...ri+1+1=maxx ,其中 maxi 表示未被排序的第i大数。
这样就明确了:先处理出来新的操作序列,然后对于每两个操作序列之间的区间,依次放入最大值、次大值…或依次放入最小值、次小值…,可以通过对原数组排序后得到,具体看代码
挺好的一个乱搞题
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int SZ = 1000010;
struct haha{
int r,opt;
}S[SZ];
int top = 0;
bool cmp1(int a,int b) { return a < b; }
bool cmp2(int a,int b) { return a > b; }
int num[SZ],tmp[SZ];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++)
scanf("%d",&num[i]),tmp[i] = num[i];
for(int i = 1;i <= m;i ++)
{
int opt,r;
scanf("%d%d",&opt,&r);
while(top && r >= S[top].r) top --;
S[++ top] = (haha){r,opt};
}
sort(tmp + 1,tmp + S[1].r + 1,cmp1);
S[top + 1].r = 0;
int ll = 0,rr = S[1].r + 1;
// puts("");
for(int i = 1;i <= top;i ++)
{
int r = S[i].r,opt = S[i].opt,r1 = S[i + 1].r + 1;
// cout<<r1<<" "<<r<<" "<<opt<<endl;
for(int j = r;j >= r1;j --)
if(opt == 1)
num[j] = tmp[-- rr];
else
num[j] = tmp[++ ll];
//for(int i = 1;i <= n;i ++) printf("%d ",num[i]); puts("");
}
for(int i = 1;i <= n;i ++) printf("%d ",num[i]);
return 0;
}
/* 5 5 5 4 3 2 1 1 5 2 4 1 3 2 2 1 1 */
求B串在A串中出现多少次,其中字符串是这样给定的:n/m组 li−ci 表示当前位置有连续 li 个 ci 。n和m是20万, li 是一百万。
SBkmp,打错变量名和没开longlong毁一生QAQ
先把输入中相邻两个字母相同的合并。
然后,若B串在A串中出现,当且仅当B[1,m-2]和A[i,j]完全匹配(字母和数字完全一样);B[0]的字母和A[i-1]一样,B[0]的数字小于等于A[i-1]的数字;B[m-1]的字母和A[j+1]一样,B[m-1]的数字小于等于A[j+1]的数字。
说白了就是B串去掉头和尾然后做kmp,统计答案的时候特判一下头和尾是否合法就行了。对于m=1和m=2的情况单独处理。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int SZ = 1000010;
struct haha{
LL d;
char c;
}aa[SZ],bb[SZ],a[SZ],b[SZ],tmp[SZ];
bool operator != (haha a,haha b)
{
return a.d != b.d || a.c != b.c;
}
bool operator == (haha a,haha b)
{
return a.d == b.d && a.c == b.c;
}
int n,m;
int nxt[SZ];
void getnxt(haha a[],int n)
{
nxt[0] = nxt[1] = 0;
for(int i = 1;i < n;i ++)
{
int j = nxt[i];
while(j && a[i] != a[j]) j = nxt[j];
nxt[i + 1] = a[i] == a[j] ? j + 1 : 0;
}
}
LL kmp(haha a[],haha b[],haha c[])
{
getnxt(a,m - 2);
LL ans = 0,len = m - 2;
for(int i = 0,j = 0;i < n;i ++)
{
while(j && b[i] != a[j]) j = nxt[j];
if(b[i] == a[j]) j ++;
if(j == len)
{
// printf("%d %d\n",i,j);
// printf("%c %c %c %c\n",c[0].c,b[i - len].c,c[m - 1].c,b[i + 1].c);
if(j - len >= 0)
{
if(c[0].c == b[i - len].c && c[m - 1].c == b[i + 1].c)
if(c[0].d <= b[i - len].d && c[m - 1].d <= b[i + 1].d)
ans ++;
}
}
}
return ans;
}
void change(haha a[],haha aa[],int &n,int n1)
{
for(int i = 0;i < n1;i ++)
{
a[n] = aa[i];
while(i < n1 - 1 && a[n].c == aa[i + 1].c)
{
a[n].d += aa[i + 1].d;
i ++;
}
n ++;
}
}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n1,m1;
scanf("%d%d",&n1,&m1);
for(int i = 0;i < n1;i ++)
scanf("%I64d-%c",&aa[i].d,&aa[i].c);
for(int i = 0;i < m1;i ++)
scanf("%I64d-%c",&bb[i].d,&bb[i].c);
change(a,aa,n,n1);
change(b,bb,m,m1);
/* for(int i = 0;i < n;i ++) printf("%d-%c ",a[i].d,a[i].c); puts(""); for(int i = 0;i < m;i ++) printf("%d-%c ",b[i].d,b[i].c); puts("");*/
if(m == 1)
{
LL ans = 0;
for(int i = 0;i < n;i ++)
{
if(a[i].c == b[0].c && a[i].d >= b[0].d)
{
ans += a[i].d - b[0].d + 1;
// printf("%d %d\n",a[i].d,b[0].d);
}
}
printf("%I64d",ans);
}
else if(m == 2)
{
LL ans = 0;
for(int i = 0;i < n - 1;i ++)
{
if(a[i].c == b[0].c && a[i + 1].c == b[1].c)
{
if(a[i].d >= b[0].d && a[i + 1].d >= b[1].d)
ans ++;
}
}
printf("%I64d",ans);
}
else
{
for(int i = 1;i < m - 1;i ++)
tmp[i - 1] = b[i];
printf("%I64d",kmp(tmp,a,b));
}
return 0;
}
/* 6 3 3-a 4-a 5-b 3-a 2-a 1-a 3-a 4-a 5-b */
弃疗,丢官方题解。
(好像要凸壳什么高端的东西才不知道呢哼)