Comet OJ Contest #3

  A:签到。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 510
char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
	while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,k,a[N],f[N*N],t;
signed main()
{
	n=read(),k=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=1;i<=n;i++)
		for (int j=i+1;j<=n;j++)
		f[++t]=a[i]+a[j];
	sort(f+1,f+t+1);reverse(f+1,f+t+1);
	ll ans=0;
	for (int i=1;i<=k;i++) ans+=f[i];
	cout<<ans;
	return 0;
	//NOTICE LONG LONG!!!!!
}

  B:找到第一个和最后一个有1的列,状压dp一下即可,即设f[i][0/1][0/1]为第i列为0/1,0/1时的最优方案要加多少个1。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 100010
char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
	while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,a[N][2],f[N][2][2],first,last,ans;
signed main()
{
	n=read();
	for (int i=1;i<=n;i++) a[i][0]=read();
	for (int i=1;i<=n;i++) a[i][1]=read();
	for (int i=1;i<=n;i++) if (a[i][0]||a[i][1]) {first=i;break;}
	for (int i=n;i>=1;i--) if (a[i][0]||a[i][1]) {last=i;break;}
	memset(f,42,sizeof(f));f[first-1][1][1]=0;
	for (int i=first;i<=last;i++)
	{
		for (int x0=0;x0<2;x0++)
			for (int x1=0;x1<2;x1++)
				for (int y0=0;y0<2;y0++)
					for (int y1=0;y1<2;y1++)
					{
						int tot=0;
						if (a[i][0]==0&&x0==1) tot++;
						if (a[i][1]==0&&x1==1) tot++;
						if (x0==1&&y0==1||x1==1&&y1==1) f[i][x0][x1]=min(f[i][x0][x1],f[i-1][y0][y1]+tot);
					}
	}
	ans=1000000000;
	for (int i=0;i<2;i++)
		for (int j=0;j<2;j++)
		ans=min(ans,f[last][i][j]);
	cout<<ans;
	return 0;
	//NOTICE LONG LONG!!!!!
}

  C:容易发现子序列中一个数的贡献是2l,而只需要考虑其是否是m的倍数,于是l超过logm后就没什么意义了。于是设f[i][j][k]为前i个数选了模m为j的k个数的方案数,转移显然。复杂度O(nmlogm),直接就可以暴力过去。事实上应该是可以做到O(nm)的,因为只需要考虑模m/2k的值。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 5010
#define P 1000000007
char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
	while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,m,a[N],f[15][N],g[N],t;
inline void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
inline int dec(int x,int y){x-=y;if (x<0) x+=m;return x;}
signed main()
{
	n=read(),m=read();int tmp=m;while (tmp%2==0) t++,tmp>>=1;t++;
	for (int i=1;i<=n;i++) a[i]=read();
	f[0][0]=1;
	for (int i=1;i<=n;i++)
	{
		for (int j=0;j<m;j++) g[j]=f[t][j];
		for (int j=0;j<m;j++) inc(f[t][j],g[dec(j,a[i])]);
		for (int k=t;k;k--)
		{
			for (int j=0;j<m;j++)
			{
				inc(f[k][j],f[k-1][dec(j,a[i])]);
			}
		}
	}
	int ans=0;
	for (int i=0;i<m;i++)
		for (int j=1;j<=t;j++)
		{
			int x=i;for (int _=1;_<j;_++) x=(x<<1)%m;
			if (x==0) inc(ans,f[j][i]);
		}
	cout<<ans;
	return 0;
	//NOTICE LONG LONG!!!!!
}

  D:差分序列,则区间修改变成单点修改,然后只要维护区间线性基即可,注意要强制令第一个数是否选,这样才能考虑完选偶数个数和奇数个数的情况。开始莫名其妙想成了前缀和,然后发现了一个选奇数个数的最大异或和的做法,即将每个数比最高位更高的一位设为1。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 50010
#define P 1000000007
#define uint int
char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
	while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,m,L[N<<2],R[N<<2],tree_o[N];
int a[N],mx;
void  modify_o(int x,int y){while (x<=n) tree_o[x]^=y,x+=x&-x;}
int query_o(int x){int s=0;while (x) s^=tree_o[x],x-=x&-x;return s;}
struct base
{
	int b[32];
	void ins(int v)
	{
		for (int i=30;~i;i--)
		if (v&(1<<i))
		{
			if (b[i]==0) {b[i]=v;return;}
			else v^=b[i];
		}
	}
	int work(int v)
	{
		for (int i=30;~i;i--) v=max(v,v^b[i]);
		return v;
	}
	void clear(){memset(b,0,sizeof(b));}
}tree[N<<2],e;
base merge(base x,base y)
{
	for (int i=30;~i;i--)
	if (x.b[i]) y.ins(x.b[i]);
	return y;
}
void build(int k,int l,int r)
{
	L[k]=l,R[k]=r;
	if (l==r) {tree[k].ins(a[l]);return;}
	int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	tree[k]=merge(tree[k<<1],tree[k<<1|1]);
}
void modify(int k,int x,int p)
{
	if (L[k]==R[k]) {tree[k].clear();a[x]^=p;modify_o(x,p);tree[k].ins(a[x]);return;}
	int mid=L[k]+R[k]>>1;
	if (x<=mid) modify(k<<1,x,p);
	else modify(k<<1|1,x,p);
	tree[k]=merge(tree[k<<1],tree[k<<1|1]);
}//给x xor 上p
base query(int k,int l,int r)
{
	if (l>r) return e;
	if (L[k]==l&&R[k]==r) return tree[k];
	int mid=L[k]+R[k]>>1;
	if (r<=mid) return query(k<<1,l,r);
	else if (l>mid) return query(k<<1|1,l,r);
	else return merge(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
}//区间线性基
signed main()
{
	n=read(),m=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=n;i;i--) a[i]^=a[i-1],modify_o(i,a[i]);
	build(1,0,n);
	while (m--)
	{
		int op=read(),l=read(),r=read();
		int v=read();
		if (op==1)
		{
			modify(1,l,v);
			if (r<n) modify(1,r+1,v);
		}
		else
		{
			int ans=max(query(1,l+1,r).work(v),query(1,l+1,r).work(v^query_o(l)));
			printf("%d\n",ans);
		}
	}
	return 0;
	//NOTICE LONG LONG!!!!!
}

  小裙子!

原文地址:https://www.cnblogs.com/Gloid/p/10859062.html

时间: 2024-07-30 12:53:41

Comet OJ Contest #3的相关文章

Comet OJ - Contest #5

Comet OJ - Contest #5 总有一天,我会拿掉给\(dyj\)的小裙子的. A 显然 \(ans = min(cnt_1/3,cnt_4/2,cnt5)\) B 我们可以感性理解一下,最大的满足条件的\(x\)不会太大 因为当\(x\)越来越大时\(f(x)\)的增长速度比\(x\)的增长速度慢得多 其实可以证明,最大的满足的\(x\)不会超过\(100\) 因为没有任何一个三位数的各位之和大于等于\(50\) 所以我们就直接预处理\(1-99\)所有的合法的 暴力枚举即可 其实

符文能量(Comet OJ - Contest #8)

给Comet OJ打个小广告,挺好用的,比较简洁,给人感觉很好用 Contest #8是我打的第一场本oj比赛,很遗憾A了前两道傻逼题就没思路了,然后就不打算打了....... https://www.cometoj.com/contest/58/problem/C?problem_id=2760 怎么做啊完全不会啊我那么菜,虽然看到是dp但嫌太麻烦就放弃了: 靠后仔细想了想原来这道题很简单: 结构体node e[];储存ai,bi值(当然你用数组我也不拦着),因为合并的方式很特殊,可以不管合并

Comet OJ - Contest #10 B

Comet OJ - Contest #10 B 沉鱼落雁 思维题 题意 : 每个数字最多重复出现三次,有n给数字,让你尽可能的使得相同数字之间的最小距离尽可能大 思路 :分三种情况套路 设 a b c 分别代表出现 一次, 两次, 三次 数字的个数 所有元素至多出现一次,答案为 n,题目规定 所有元素至多出现两次, 例如 1 1 2,可以排列成 1 2 1,所以,答案为 1 例如 1 1 2 2 3,可以排列成 1 2 3 1 2,所有 答案为 2 思考后得出,应该尽可能的把 b 个出现两次的

Comet OJ - Contest #7 解题报告

传送门:https://www.cometoj.com/contest/52 A:签到题 题意:多次询问,每次询问给出一个值域区间[l,r],从这区间范围中选出两个整数(可重复),依次求出这俩数的“最大的最小公倍数”.“最小的最小公倍数”.“最大的最大公约数”.最小的最大公约数. 分析:(1)显然,当区间长度为1时,该问题的答案只能是区间中仅有的那个数. (2)当区间的长度大于1时,最大的最小公倍数,lcmmax =lcm(ar,ar-1) = ar * ar-1: 最小的最小公倍数,lcmmi

Comet OJ - Contest #15

https://cometoj.com/contest/79/problem/D?problem_id=4219 题目描述 ※ 简单版与困难版的唯一区别是粗体字部份和 $v$ 的数据范围. 在双 11 时,心慧精品店有个特别的折价活动如下: 首先,我们定义一个正整数为"好的"当且仅当此数仅由数字 1 构成,举例来说 1, 11, 111, 11111 都是「好的」,但 10.123.321 都是「不好的」. 接着,若一个商品原价为 x,若顾客能把 x 表示为 k 个「好的」数字,那么此

Comet OJ - Contest #15题解

A 双十一特惠 (简单版) n  <=  1e19,   1e9 > 1(8) https://www.cometoj.com/contest/79/problem/A?problem_id=4198 #include<bits/stdc++.h> using namespace std; int main(){ int t; cin >> t; while(t--) { int cnt1 = 0; int n;cin >> n; int pr[] = {1

Comet OJ - Contest #0

A:化成x-√n=y+z-√4yz的形式,则显然n是完全平方数时有无数组解,否则要求n=4yz,暴力枚举n的因数即可.注意判断根号下是否不小于0. #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long

Comet OJ - Contest #1

A:随便怎么暴力. #include<bits/stdc++.h> using namespace std; #define ll long long #define N 25 char getc(){char c=getchar();while (c!='.'&&c!='#') c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char

Comet OJ Contest #2

A:暴力,显然每两次至少翻一倍. #include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} in