首页 > 其他分享 >题解:USACO23OPEN-Silver

题解:USACO23OPEN-Silver

时间:2023-11-02 20:35:40浏览次数:36  
标签:USACO23OPEN int 题解 sum unsigned long bessie Silver define

题解:USACO23OPEN-Silver

T1 Milk Sum

给定一个长度为 \(N\) 的序列 \(a_1,a_2,...,a_n\),现在给出 \(Q\) 次操作每次将 \(a_x\) 修改为 \(y\) , 每次修改后,求将序列重排后的 \(T\) 的最大值,定义 \(T=\sum_{i=1}^{n}i \times a_i)\)

每次修改数组后会将序列还原成原样(修改不继承)

有一个显然的结论:对于\(\forall 0<a<b, 0<c<d\) ,满足\(a*c+b*d<a*d+b*c\)

所以将序列从小到大排序得到的 \(T\) 一定更大

所以预先把排好的原序列存下来,对于每次修改只需要二分出修改后应放的位置,然后(1)减掉原来数的贡献,(2)加上现在数的贡献,(3)所有位置后挪1或前挪1的贡献变化

#include<bits/stdc++.h>
using namespace std;
#define F(i,l,r) for(int i=l;i<=r;++i)
#define G(i,r,l) for(int i=r;i>=l;--i)
#define ll long long
#define ull unsigned long long
#define mem(a) memset(a,0,sizeof(a))
const int N=2e5+5;
int n,q;
struct node{ int id; ll x; }a[N];
ll b[N],c[N];
ull sum[N],tot=0;
inline bool cmp1(const node &u,const node &v){ return u.x==v.x ? u.id<v.id : u.x<v.x; }
inline bool cmp2(const node &u,const node &v){ return u.id<v.id; }
int main(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	scanf("%d",&n);
	F(i,1,n) scanf("%lld",&a[i].x),a[i].id=i;
	sort(a+1,a+n+1,cmp1);
	F(i,1,n) b[i]=a[i].x,c[a[i].id]=i;
	F(i,1,n) sum[i]=sum[i-1]+b[i],tot+=1ll*b[i]*i;
	sort(a+1,a+n+1,cmp2);
	scanf("%d",&q); while(q--){
		int i,j;
		scanf("%d %d",&i,&j);
		int w=upper_bound(b+1,b+n+1,j)-b;
		if(a[i].x<j){//bigger
			--w;
//			printf("w1=%d\n",w);
			ull res=tot-1ull*a[i].x*c[i]+1ull*w*j-(sum[w]-sum[c[i]]);
			printf("%llu\n",res);
		}
		else if(a[i].x==j) printf("%lld\n",tot);
		else{//smaller
			ull res=tot-1ull*a[i].x*c[i]+1ull*w*j+(sum[c[i]-1]-sum[w-1]);
			printf("%llu\n",res);
		}
	}
	return 0;
}

T2 Field Day

(又是逆向思维题...)

给出 \(N\) 个长度为 \(C\) 的 \(GH\) 串,将 \(G\) 看作 \(0\) ,将 \(H\) 看作 \(1\) , 则每个串可看做01串,对于每个 \(i\) ,求 \(max_{j=1}^{n} popcount(a_i \oplus a_j)\)

\(2 \leq N \leq 10^5,1 \leq C \leq 18\)

暴力是 \(O(N^2)\) 的,发现本题的特点如下:

(1) \(C\) 很小,算一下本质不同的 \(01\) 串只有 \(2^{18}\) 个,大概是25万多一点。

※(2)最大值不是很好求,考虑倒过来想,转化成求最小值。

(3)与串 \(a_i\) 差异度为 \(k\) 的一个串 \(t\) 可以看做是 将 \(a_i\) 的其中 \(k\) 个数一步一步取反后得到的。

一个数可以由多个给出的串通过这样的取反变化得到,但我们只关心至少要改变几个数位才能得到 \(t\)(求最小值嘛),所以如果我们能找到一种操作顺序,使第一次得到 \(t\) 花的就是最少步数的话,那\(0-2^c-1\) 下的每个数都只需要访问一遍就可以了!

什么样的操作顺序使我们需要的呢?灵光一现,考虑广搜,先搜出每个串改1个数位能得到的结果,再考虑改2个数,再改3个,4个....一直到 \(c\) 个,每次都把上一层更新出的数存下来用于下一层更新,访问过的数不再重复访问,时间复杂度 \(O(2^C)\)。

广搜写法:

#include<cstdio>
#include<queue> 
using namespace std;
#define ri register int
#define F(i,l,r) for(ri i=l;i<=r;++i)
const int N=1e5+5;
queue<int> q;
int c,n,a[N],f[(1<<18)+100];
char s[22];
bool vis[(1<<18)+100];
int main(){
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
	scanf("%d%d",&c,&n);
	F(i,1,n){
		scanf("%s",s+1);
		int sum=0;
		F(j,1,c) sum=(sum<<1)+(s[j]=='G');
		a[i]=sum; q.push(sum); vis[sum]=1;
	}
	while(q.size()){
		int x=q.front();q.pop();
		F(i,1,c){
			int y=x^(1<<(i-1));
			if(vis[y] || f[y]) continue;
			f[y]=f[x]+1; 
			vis[y]=1; q.push(y);
		}
	}
	F(i,1,n) printf("%d\n",c-f[(1<<c)-1-a[i]]);
	return 0;
}

用循环模拟广搜:

#include<cstdio>
using namespace std;
#define ri register int
#define F(i,l,r) for(ri i=l;i<=r;++i)
#define min(x,y) x<y?x:y
const int N=1e5+5;
int sum,c,n,a[N],f[(1<<18)+100];
char s[22];
int main(){
	freopen("b.in","r",stdin); freopen("b.out","w",stdout);
	scanf("%d%d",&c,&n);
	F(i,0,(1<<c)-1) f[i]=99999999;
	F(i,1,n){
		scanf("%s",s+1); 
		sum=0;
		F(j,1,c) sum=(sum<<1)+(s[j]=='G');
		f[sum]=0; 
		a[i]=sum;
	}
	F(i,1,c) F(j,0,(1<<c)-1) f[j^(1<<i-1)]=min(f[j^(1<<i-1)],f[j]+1);
	F(i,1,n) printf("%d\n",c-f[(1<<c)-1-a[i]]);
	return 0;
}

T3 Pareidolia

给定一个仅包含小写字母的字符串 \(s\) , 长度不超过 \(3 \times 10^5\)。

定义函数 \(B(s)\) 表示把 \(s\) 中的若干个字母删去后,形成尽量多个bessie相连的形式(bessiebessiebessie...),返回bessie的最大数量。

如 \(B(\text{"bqessiyexbesszieb"})=2\)。

求 \(s\) 的所有子串的 \(B\) 函数之和。

两个误区:

(1)一个字符最多只能存在于一个bessie中而非多个。还担心会不会一匹配多,把问题想复杂了

(2)审题不清:没发现任意字母都可以删去,还以为是KMP,写到最后再读题发现问题之后哭死,只剩不到1h,直接失去继续写下去的动力了。。。(想好再下笔!!!)

对我来说,光是如何简明地书写判断是否找到了一个新的bessie都有难度。。。

由于模式串是固定的而且只有六位,直接对于 b,e,s,i这几种字符记录我所在的bessie串的开头b所在的位置即可。开头记录下来,串的位置当然也就确定啦!而且后面统计答案还要用到

考虑新发现一个bessie串对答案的贡献。记 \(f_i\) 为以i结尾的所有子串的B函数之和,\(pos\) 为新发现的bessie串的开头位置。则有

\[f_i=f_{pos-1}+pos \]

emm...可以感性理解为:继承没发现这个串之前的答案 + 起点为1-pos,终点固定成i的所有串都会多看到当前这个新串。

最终答案 \(sum=\sum_{i=1}^{n} f_i\)

注意有些字符的更新是有顺序的,不要写挂了。

#include<cstdio>
const int N=3e5+5;
char s[N];
int p[10];
long long f[N],sum=0;
int main(){
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	scanf("%s",s+1);
	for(int i=1;s[i];++i){
//		F(i,1,6) printf("%d ",p[i]); puts("");
		if(s[i]=='b') p[1]=i;
		else if(s[i]=='e') p[2]=p[1],p[6]=p[5];
		else if(s[i]=='s') p[4]=p[3],p[3]=p[2];//不能写反,否则一个's'会同时更新p[4],p[3] 
		else if(s[i]=='i') p[5]=p[4];
		if(p[6]) f[i]=f[p[6]-1]+p[6];
		//f[i]:以i结尾的所有子串的B函数之和 
		//p[6]:以i结尾的能含有当前这个新增bessie的子串的数量
		//p[6]位置以前的所有串还能多包含一个bessie(即当前新增的这个),所以要+f[p[6]-1] 
		sum+=f[i];
	} printf("%lld",sum);
	return 0;
}

存疑:为什么下面这种写法是错的???

#include<bits/stdc++.h>
using namespace std;
char c[300005];
unsigned long long p[10];
int main(){
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	scanf("%s",c+1);
	unsigned long long lenc=strlen(c+1);
	unsigned long long ans=0;
	unsigned long long sum=0;
	for(unsigned long long i=1;i<=lenc;i++){
		if(c[i]=='b') p[1]=i;
		if(c[i]=='e'){
			p[2]=p[1];
			if(p[5]!=p[6]) sum+=p[5];
			p[6]=p[5];
		}
		if(c[i]=='s') p[4]=p[3],p[3]=p[2];
		if(c[i]=='i') p[5]=p[4];
		ans+=sum;
	}
	printf("%llu",ans);
	return 0;
}

模拟赛总结:

1.感觉T1写了近两个小时有点慢了,如果把找 \(a_x\) 原位置直接也写成lower_bound可能会节省很多时间(毕竟每写一个二分查总是要调很久...)

2.T2部分分拿的还是很稳的,但对于C较小这个性质的运用还是差了些:只想到了用bitset优化异或过程。还有,积累逆向思维的经验:原问题不好想,那就承认它不好想,就大胆考虑倒过来想

(由于正着做不好想,所以我们考虑倒过来想)

3.T3首先审题不清(想好再下笔),第二想复杂了,被吓到了(还是要多手玩几个样例去自己体会题目的要求,不要偷懒 ~ ~ ~)

写在最后:距离NOIP2023仅剩16天,耳边又想起了中考前我的语文老师告诉我的那句话,

“行百里者半九十。”

希望不留遗憾~加油NOIP2023!

标签:USACO23OPEN,int,题解,sum,unsigned,long,bessie,Silver,define
From: https://www.cnblogs.com/superl61/p/17806221.html

相关文章

  • CF773A Success Rate 题解
    SuccessRate(提供二分做法)前言听说是史上最简单蓝题,做了一下。题意已知\(x,y,p,q\),通过只让\(y\)加\(1\)或\(x,y\)同时加\(1\),使得满足:\[\frac{x'}{y'}=\frac{p}{q}\]思考目标状态为\(\frac{p}{q}\),考虑到这是个比值,自然\(\frac{x'}{y'}=\frac{kp}{kp}\)。明显......
  • 【POJ 1256】Anagram 题解(全排列)
    描述你要编写一个程序,从一组给定的字母中生成所有可能的单词。示例:给定单词“abc”,您的程序应该-通过探索这三个字母的所有不同组合-输出单词“abc”、“acb”、“bac”、“bca”、“cab”和“cba”。在输入文件中的单词中,某些字母可能出现多次。对于给定的单词,您的程序不应多次......
  • CF1868B2 Candy Party (Hard Version) 题解
    Problem-1868B2-CodeforcesCandyParty(HardVersion)-洛谷相信大家已经看过SimpleVersion,这题和上题不同之处就在于如果\(b_i=2^x\),他可以被分解成\(2^x\)或\(2^{x+1}-2^x\),我们不妨起初固定一种方案,如果不满足条件后再把一部分换回去。我们强制钦定起......
  • CF227A Where do I Turn? 题解
    题目大意:\(A\),\(B\)在一条直线上。\(B\),\(C\)在一条直线上你从\(A\)走到了\(B\)去\(C\),问现在应该是直走、左转、还是右转。思路:分类讨论:分别求\(A\)到\(B\),\(B\)到\(C\)是什么方向,然后可得\(A\)到\(C\)的方向。Code:#include<bits/stdc++.h>usingnamesp......
  • CF333B题解
    分析发现只能跳\(n-1\)次,所以每个点一定是畅通无阻地抵达终点,所以有障碍的行和列放不了,并且每一个行或列最多放一个。因为同时跳,思考会不会跳到一起,发现如果不在正中间可以将起点放到另一头就不会跳到一起,如果在正中间就一定会跳到一起,所以正中间的行和列加一起最多只能放......
  • CF333A题解
    分析被除数一定,除数越小,商越大,所以选择合法的最小\(3_{x}\)。枚举指数即可,复杂度\(\mathcal{O(\log_{3}w)}\),\(w\)为值域\(1e18\),可以通过本题。代码#include<iostream>#defineintlonglongusingnamespacestd;constexprintMAXN(1000007);intf[MAXN];int......
  • P9740 「KDOI-06-J」ION 比赛 题解
    题目思路:先计算总分数\(sum\),\(c_i=\frac{100}{a_i}\)为每道题的每个测试点分数。如果总分数达到\(Au\)线,直接输出AlreadyAu.。否则计算到达\(Au\)线还需多少分\(p\),遍历所有题,求出每道题的失分,如果失分大于等于\(p\),则输出\(\lceil\frac{p}{c_i}\rceil\),即至......
  • Educational Codeforces Round 134 (Div.2) D 题解
    题目链接D.MaximumAND题目大意给定两组序列\(a\)\(b\),长度为\(n\),现有一新序列\(c\),长度也为\(n\)。其中,\(c_i=a_i\oplusb_i\)。定义\(f(a,b)=c_1\&c_2\&……\&c_n\)。现在你可以随意编排\(b\)序列的顺序,求\(f(a,b)\)的最大值。思路以下位运算均是......
  • 【python】-bash: /usr/local/bin/pip: /usr/bin/python: bad interpreter: No such f
    安装单独的第三方库时没有问题pipinstallpandas但是一旦使用requirement.txt批量安装第三方库时就会出现-bash:/recorddata/rebuydata/hppy/soft/python3/bin/pip3:/usr/local/source/hppy/soft/python3/bin/python3.6:badinterpreter:没有那个文件或目录badinterpreter......
  • CF1868B1 Candy Party (Easy Version) 题解
    Problem-1868B1-CodeforcesCandyParty(EasyVersion)-洛谷喵喵题。首先每个数最终肯定变成\(\overlinea\),如果\(\overlinea\)不是整数显然无解。然后记\(b_i=a_i-\overlinea\)表示每个数的偏差量,那\(b_i\)要满足能写成\(2^x-2^y\)的形式然后只需要......