[NOI Online #3 提高组]

Preface

NOIOL的实质竟然是卡常数大赛吗,爱了爱了

话说我终于相信了这个系列的比赛难度都是蓝题了。(虽然第一场翻车翻到天上了)

PS:如果让开O2就AK了(flag),不给开就炸成100……


[NOI Online #3 提高组]水壶

正常人都知道只选一个水壶的话答案显然就是连续的\(k+1\)个数的和的最大值

由于没有负数所以直接前缀和即可

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=1000005;
int n,k,a[N],pfx[N],ans;
int main()
{
	freopen("kettle.in","r",stdin); freopen("kettle.out","w",stdout);
	RI i; for (scanf("%d%d",&n,&k),++k,i=1;i<=n;++i)
	scanf("%d",&a[i]),pfx[i]=pfx[i-1]+a[i];
	for (i=1;i<=n;++i) ans=max(ans,pfx[i]-pfx[i>=k?i-k:0]);
	return printf("%d",ans),0;
}

[NOI Online #3 提高组]魔法值

容易想到这种异或的题目考虑求出每个点对答案的贡献

建出原图的邻接矩阵,考虑转移的时候就是一个对\(2\)取余的矩阵乘法,然后这样的复杂度是\(O(q\times n^3\log n)\)

然后应该开始思考\(O(q\times n^2\log n)\)做法我们发现这个矩乘的过程可以看做拿出一行和一列\(\operatorname{and}\),然后考虑\(1\)的个数的奇偶性即可

bitset维护行列信息,复杂度就是\(O(\frac{q\times n^3\log n}{32})\)

然后跑一发极限数据,4.5s难受,开一发O2,2.5s显然过不了啊

不要灰心我们细细一想这题\(n\le 100\),我拿两个ull就可以存下所有信息,所以干脆直接手写bitset

写完了跑一发1.2s就NM离谱,没事我们加上O2,700ms卡过……

PS:不要问我NOIOL可不可以手开O2

#pragma GCC optimize(3)
#include<cstdio>
#include<cstring>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
typedef unsigned long long u64;
const int N=105;
int n,m,q,x,y,cnt[65536]; long long p,ans,a[N];
inline void Set(u64 *p,CI x)
{
	if (x<64) p[0]|=1ull<<x; else p[1]|=1ull<<x-64;
}
inline int Cnt(const u64& x)
{
	return cnt[x&65535]^cnt[(x>>16)&65535]^cnt[(x>>32)&65535]^cnt[x>>48];
}
struct Matrix
{
	int n,m; u64 h[N][2],l[N][2];
	inline Matrix(CI N=0,CI M=0)
	{
		n=N; m=M; memset(h,0,sizeof(h)); memset(l,0,sizeof(l));
	}
	friend inline Matrix operator * (Matrix A,Matrix B)
	{
		Matrix C(A.n,B.m); for (RI i=0,j;i<C.n;++i)	for (j=0;j<C.m;++j)
		if (Cnt(A.h[i][0]&B.l[j][0])^Cnt(A.h[i][1]&B.l[j][1]))
		Set(C.h[i],j),Set(C.l[j],i); return C;
	}
	friend inline Matrix operator ^ (Matrix A,long long p)
	{
		Matrix T(A.n,A.m); for (RI i=0;i<T.n;++i) Set(T.h[i],i),Set(T.l[i],i);
		for (;p;p>>=1,A=A*A) if (p&1) T=T*A; return T;
	}
};
int main()
{
	freopen("magic.in","r",stdin); freopen("magic.out","w",stdout);
	RI i; scanf("%d%d%d",&n,&m,&q); Matrix G(n,n);
	for (i=1;i<65536;++i) cnt[i]=cnt[i>>1]^(i&1);
	for (i=0;i<n;++i) scanf("%lld",&a[i]); for (i=1;i<=m;++i)
	scanf("%d%d",&x,&y),--x,--y,Set(G.h[x],y),Set(G.l[y],x),Set(G.h[y],x),Set(G.l[x],y);
	while (q--)
	{
		scanf("%lld",&p); Matrix T=G^p; for (ans=i=0;i<n;++i)
		if (T.h[i][0]&1) ans^=a[i]; printf("%lld\n",ans);
	}
	return 0;
}

[NOI Online #3 提高组]优秀子序列

这题和[CTSC2017]吉夫特很像,都是标算\(O(2^n\times n^2)\)然后被\(O(3^n)\)艹过

首先显然考虑求出每个数出现的次数,然后考虑选出的子序列的性质,显然是不能在某一个二进制位上有两个及以上的\(1\)

因此子序列的和就是\(a_i\)级别的了,我们考虑直接DP维护它,设\(f_i\)表示子序列的和为\(i\)的方案数

然后转移的时候因为同一位上不能有多的\(1\),因此转移就是枚举子集\(j\),这个是\(O(3^n)\)

然后注意一下转移的时候判一下\(j>i\operatorname{xor}j\)防止重复转移,然后直接算答案即可

PS:注意\(0\)的贡献要单独算,初值要赋成\(2^{c_0}\)

PPS:不开O2过不去233……

PPPS:听说有julao写了FWT+EXP的,然后还没暴力快的说……

#pragma GCC optimize(3)
#include<cstdio>
#define RI register int
#define CI const int&
using namespace std;
const int N=262144,mod=1e9+7;
int n,x,c[N],f[N],phi[N+5],prime[N+5],cnt,ans; bool vis[N+5];
#define P(x) prime[x]
inline void init(CI n=N)
{
	RI i,j; for (vis[1]=phi[1]=1,i=2;i<=n;++i)
	{
		if (!vis[i]) prime[++cnt]=i,phi[i]=i-1;
		for (j=1;j<=cnt&&i*P(j)<=n;++j)
		{
			vis[i*P(j)]=1; if (i%P(j)) phi[i*P(j)]=phi[i]*(P(j)-1);
			else phi[i*P(j)]=phi[i]*P(j);
		}
	}
}
#undef P
inline void inc(int& x,CI y)
{
	if ((x+=y)>=mod) x-=mod;
}
int main()
{
	freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout);
	RI i,j; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&x),++c[x];
	for (f[0]=i=1;i<=c[0];++i) inc(f[0],f[0]);
	for (i=1;i<N;++i) for (j=i;;j=(j-1)&i)
	{
		if (j>(i^j)) inc(f[i],1LL*c[j]*f[i^j]%mod); if (!j) break;
	}
	for (init(),i=0;i<N;++i) inc(ans,1LL*phi[i+1]*f[i]%mod);
	return printf("%d",ans),0;
}

Postscript

CCF送温暖,下次还要继续呦

5/27Upt:woc就我被卡成了290……\kel

posted @ 2020-05-24 15:52  空気力学の詩  阅读(290)  评论(2编辑  收藏  举报