CSP2020复赛前小结

今天用windows下的GUIDE打了一些板子,以下是我遇到的问题。

语言

未定义返回值类型的函数

inline isnum(char ch)
{
	return ch>='0'&&ch<='9';
}
inline int read()
{
	int x=0,fu=1;
	char ch=getchar();
	while(!isnum(ch)&&ch!='-') ch=getchar();
	if(ch=='-') fu=-1,ch=getchar();
	while(isnum(ch)) x=x*10+ch-'0',ch=getchar();
	return x*fu;
}

上面是一个快读。isnum(char)忘记写返回值了,但是信息查看栏里面

--------开始编译--------
编译成功.

居然没有报错。

交到洛谷上

ISO C++ 不允许声明无类型的‘isnum’ [-fpermissive]
 inline isnum(char ch)

这就很麻烦了啊。考试的时候别看见inline就忘记返回值了!


其实c++有一个在<cstdio>内的函数isdigit(char)可以用来判断是否为数字。

这是我一般写的快读(没有负数)

inline int read()
{
	int x=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    x=ch-'0';ch=getchar();
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x;
}

读入string

大家应该都知道,读入string字符串一般用cin>>string。但是如果想要快一点的话,如何读入呢?用scanf

使用scanf的话,格式符是"%s",并且string变量名不能像char数组那样当作首元素的指针了,应该使用取地址符来进行读入。

string a;
scanf("%s",&a[0]);

看似很完美也很快的方法,结果读入了什么都没有!这是为什么?

因为string属于\(STL\)的容器,这些容器以开始都是没有分配内存的,需要手动分配内存。

string a;
a.resize(10);//这个长度要手动设置
scanf("%s",&a[0]);

所以我还是打算老老实实的使用cin呢。

当然有人要问,为什么不用getchar()再插入。因为string.push_back()\(C++11\)的语言了,csp应该是不能用。。。

栈大小

编译开大:

-Wl,-stack=67108864

总体开大:

sudo -s//管理员权限
ulimit -s unlimited//开大
ulimit//检查

算法

快速幂

可能会遇到模数为1的情况。所以别忘记给ans先%一个p或最后再%p一次

一般写法:

for(ans=1;b;b>>=1,a=a*a%p) if(b&1) ans=a*ans%p;

要改成

for(ans=1%p;b;b>>=1,a=a*a%p) if(b&1) ans=a*ans%p;

for(ans=1;b;b>>=1,a=a*a%p) if(b&1) ans=a*ans%p;ans%=p;

hack:1 0 1

因为b=0,故使用第一种程序时,不会取模,导致答案错误期望0,读到1

质数筛

埃氏筛没有问题,但是在洛谷上跑的时候最多40pts(不加快写20pts),这里就体现了快写线性筛的必要性。

book[1]=1;
for(re LL i=2;i<=n;i++)
{
    if(!book[i]) prime[size++]=i,write(i);
    for(re LL j=0;j<size&&i*prime[j]<=n;j++)
    {
        book[i*prime[j]]=1;
        if(i%prime[j]==0) break;
    }
}

树状数组

树状数组有个O(1)插入的方法

for(re int i=1;i<=n;i++)
{
	a[i]+=read();
	if(i+(i&-i)<=n) a[i+(i&-i)]+=a[i];
}

结果我两次把\(1\)看成\(i\),一次忘记判断i+(i&-i)<=n,挂的可快了!

单调队列

这里只列出来求区间最小值。

  • 一定要先判断队列不为空

  • 队尾出不单调元素

  • 插入下标进队尾

  • 队头出过期元素

记着这些应该就没问题。

while(!mn.empty()&&a[mn.back()]>a[i]) mn.pop_back();
mn.push_back(i);
while(!mn.empty()&&mn.front()+k<=i) mn.pop_front();
if(i>=k) cout<<a[mn.front()]<<" ";

KMP

还是char好用,char下标可以从1开始

for(int i=2,j=0;i<=tl;i++)
{
	while(j&&t[i]!=t[j+1]) j=nxt[j];
	if(t[i]==t[j+1]) j++;
	nxt[i]=j;
}
for(int i=1,j=0;i<=pl;i++)
{
	while(j&&(p[i]!=t[j+1])) j=nxt[j];
	if(p[i]==t[j+1]) j++;
	if(j==tl) cout<<i-tl+1<<endl,j=nxt[j];
}

string只能从0开始,好可怜。。。

int j=-1;
nxt[0]=-1;
for(int i=1;i<b.size();i++)
{
	while(j>-1&&b[i]!=b[j+1]) j=nxt[j];
	if(b[i]==b[j+1]) j++;
	nxt[i]=j;
}
j=-1;
for(int i=0;i<a.size();i++)
{
	while(j>-1&&a[i]!=b[j+1]) j=nxt[j];
	if(a[i]==b[j+1]) j++;
	if(j==b.size()-1){
		cout<<i-b.size()+2<<endl;
		j=nxt[j];
	}
}

逆元

记住三种就好

快速幂

\[a^{-1}=a^{p-2}(\texttt {mod }p) \]

拓展欧几里得

void exgcd(int a,int b,LL &x,LL &y)
{
	if(!b)
	{
		x=1;
		y=0;
		return;
	}
	exgcd(b,a%b,y,x);
	y-=a/b*x;
}
//------------
exgcd(a,p,x,y);
x=(x%p+p)%p;
cout<<x;

线性

LL inv[100000010];
LL n,p=998244352;
int main()
{
	cin>>n;
	inv[0]=1;
	inv[1]=1;
	for(LL i=2;i<=n;i++)
	{
		inv[i]=(p-p/i)*inv[p%i]%p;
	}
	for(int i=1;i<=n;i++) cout<<inv[i]<<" ";
	return 0;
}

End

检查long long,不确定就全开吧!

检查数组大小,无向图双倍,线段树四倍

删除Debug

检查freopen和选手文件夹

赛时

死磕T1,1h30min后估30pts无从下手优化;

看到T2,貌似是组合数学,直接\(pass\)

看到T3,想到暴力——线段树——vector存展开指令——1h30min写完暴力继续T1;

继续T1,优化至能过50pts。再用手动倍增(2000years,10k、100k、1000k、10000kyear)预估时间复杂度为\(O(q*log_{10} n)\),但是大样例3,它\(1s\)只能过一半!

卡常,检查,于是。。。

有所感动的是,赛后代码都正常……呵呵!

无论自己现在做什么,日子还是要接着过,明天的太阳还是会正常升起。

过去的事情就让它过去吧。

After-story

CSP2020复赛后日志

以及待更新

posted @ 2020-11-06 22:52  Vanilla_chan  阅读(230)  评论(0编辑  收藏  举报