Logo lxn 的博客

博客

标签
暂无

CFEDU-98-1452

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-12-03 18:37:52

1452E Two Editorialsbrute force, dp, greedy, sortings, two pointers Submit Add to favourites 2500 x1324

1452D Radio Towerscombinatorics, dp, math Submit Add to favourites 1600 x7063

1452C Two Bracketsgreedy Submit Add to favourites 800 x17468

1452B Toy Blocksbinary search, greedy, math, sortings Submit Add to favourites 1400 x12923

1452A Robot Programmath Submit Add to favourites 800

CF1452B

1.总和必需为(n-1)的倍数S 2. 找出最大的ai maxa和次大的maxaa, 如果这个数不是最大值,那么其余的数要补到最大值 如果这书数式最大值,那么其余的数补到次大值。 选任意盒子都行,实际不需要次大值。


#include<bits\/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
ll n,a[N],maxa,s1,s2,s3;
void  work(){
	maxa=-1;
	s1=s2=s3=0;
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		s1+=a[i];
		if(a[i]>maxa)maxa=a[i];
	}
	s2=s1; 
	if(s1%(n-1)!=0)s2=s1+(n-1)-s1%(n-1);
	s3=maxa*(n-1);
	
	cout<<max(s3,s2)-s1<<endl;		
}
int main(){
	int t;
	cin>>t;
	while(t--)
		work();
} 

CF1542D

注意读题审题,每个点只能被一个信号控制 4:1 3:2 f(4)=f(3) +f(1) 5:1 4:2 3:3 f(5)=f(4) +f(2)+f(0)

f(6)=f(5)+f(3)+f(1)=f(5)+f(4); f(7)=f(6)+f(4)+f(2)+f(0)=f(6)+f(5) 斐波那契 每种方案都是等概率的


#include <bits\/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int N=2e5+9;
ll  f[N];

ll qpow(ll a,ll b) {
	ll ans=1;
	while(b) {
		if(b&1)ans=ans*a%mod;
		a=a*a%mod;
		b\/=2;
	}
	return ans;
}
signed main() {
	int n;
	cin >> n;
	f[1]=1,f[2]=1;f[3]=2;
	for (int i = 3; i <= n; ++i) {
		f[i]=(f[i-1]+f[i-2])%mod;
	
	}
	cout <<qpow(qpow(2, n), mod - 2) * f[n] %mod;
	return 0;
}

[ARC156B] Mex on Blackboard -组合数学

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2023-02-22 23:05:26

题目大意: 给定一个集合,给出k次操作,每次可以取集合的一个子集,找出子集中最小的没有出现过的非负整数,记录着k个整数。问最后这k个整数有多少种不同可能的集合。



\/*
先手工做几个样例
样例1:
3 2
0 1 2 
- - 
0 0
0 1
1 1
0 2
1 2
2 2
0 3
1 3
2 3
3 3
3 4
样例2:
3 3
2 4 6 
- - -
0 0 0
0 0 1
0 1 1
0 1 2
0 1 3
 

相当与非降序的填入数字。(每个数据有可填入的最早位置)
数据非降序填入,类似P6475 [NOI Online #2 入门组] 建设城市 

\/\/集合问题,不考虑顺序,以从小到大为默认顺序。转换为多重集组合问题
回顾下隔板法解决多重集组合问题。

把8个球放入3个盒子,不允许空盒
oo|oo|oooo,放入2个分割线|| 
x1+x2+x3=8
00 11 2222 xi>0 (2 2 4)
ooo|oo|ooo (3,2,3)
000 11 222 
把8个球放入3个盒子,允许空盒 
x1+x2+x3=8 (0,0,8)
(x1+1)+(x2+1)+(x3+1)=11 (1 1 9)
*|*|*oooooooo
0 1 222,222,222 
   每个盒子删掉1个球后实际数据为22,222,222 
可填入的数据为[0,n+cnt] cnt为可以补入的数据个数 

设最后一个位置上可以填写的数为i,要想填入i,前面0-(i-1)必需都在集合内出现过。
	如果有数没有出现,那么需要再前面补上。可以用桶统计出需要补的个数m,从总数k中扣掉需要补的位置。
	那么剩下的位置就可以填写0-i之间的数值了共有(i+1)个数,可以重复填写再k-m-1个位置上,允许空盒,多重集组合。                
	*\/ 
#include <bits\/stdc++.h>
using namespace std; 
const int N=4e5+90; 
typedef long long int ll; 
const ll inf = 1e18, mod = 998244353;
ll f[N]={1,1},invf[N]={1,1},inv[N]={1,1}; 
ll a[N]; 
ll C(ll n,ll r){
	if(n<r||n<0)return 0;
	return f[n]*invf[r]%mod*invf[n-r]%mod;\/\/c(n,r)=n!\/(n-r)!\/r!; 
}
ll work(){
	ll n, k, ans = 0,sum=0;
	cin >> n >> k;
	for (ll i = 0, x; i < n; ++i) {
		cin >> x; a[x] = 1;
	}

	for (ll i = 0; i < n + k; ++i) {
		
		if (sum > k) break;\/\/能填写的最大数 
		ll m= k-sum-1;\/\/前面需要留出补k-sum个位置补数,后面第k个需要写i,可填写的位置为k-sum-1个 
		ll r=i+1;\/\/可填写的数据为0..i,多重集个数i+1 相当于把m个球放入r个盒子,允许空盒。 
		ans = (ans + C(m+ r-1, r-1)) % mod;
		sum+=1-a[i];		
	}
	return ans;
}
int main() {
\/\/	freopen("out.txt","w",stdout);
	for (ll i = 2; i <N; ++i) {
		f[i] = f[i - 1] * i % mod;
		inv[i] = (mod - (mod \/ i * inv[mod % i] % mod)) % mod;
		invf[i] = inv[i] * invf[i-1] % mod;
	}


	cout << work() << "\n";
	return 0;
}

CFEDU-142-1792

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2023-02-23 09:51:04

感觉很好的一套题目,水题也有意思。

A GamingForces,考察排序与贪心。

B Stand-up Comedian 数学,推式子。

有点意思的递推

#include<bits\/stdc++.h>
using namespace std;
const int N=20;
int a[N],n; 
int work(){
	
	int ans=0,f=0;\/\/ans为进行轮数,f为当前ab最小的分数。
	for(int i=1;i<=4;i++)cin>>a[i];
	if(a[2]>a[3])swap(a[2],a[3]);
	ans=a[1],f=a[1];
	if(f==0){
		ans=min(1,a[2]+a[3]+a[4]);
		return ans;
	}
	int tmp=min(a[3]-a[2],a[1]);\/\/a[3]>=a[2] 
	f-=tmp;
	if(a[3]-a[2]>a[1])ans=a[1]+2*a[2]+a[1]+1;\/\/a,b有a1分,
	else ans=a[1]+2*a[2]+tmp+min(f+1,a[4]);
	return ans;
}
int main(){

	int t;
	cin>>t;
	while(t--){
		cout<<work()<<endl;
	}
} 

C

排序、贪心,分析出成对出现是本题的关键,由内到外连续的升序为可以不动的数对。

\/*
最多操作n\/2次。
最后一次一定操作(1,n),逆序为(2,n-1)...(n\/2,n+1-n\/2)
                 n\/2         n\/2-1..k. 1 
最容易想到的方法是二分答案,模拟从第k次操作开始执行,看能否完成有序排列。
时间复杂度o(nlogn)

在操作的过程中,手工操作发现,
	如果只需要1次操作,那么拿出(1,n)后,数据已经有序。
	同理,如果需要k次操作,那么拿出(1..k) ... (n-k+1,n)后 
	                 剩下的k+1,k+2,...n-k-1,n-k已经有序了。 
	        3 8 1 4 5 2 6 9 7
	删掉19  3 8   4 5 2 6   7
	删掉28  3     4 5   6   7 
	用链表删除吗?删除链表o(1),判断有序o(n),复杂度太高。
	我们只需要知道剩下的3 4 5 6 7在原始数据中是连续上升子序列即可。
	找数列中最大连续上升子序列的长度。
	我们记录一x的位置,看他是否在x-1的前面。 
*\/ 
#include<bits\/stdc++.h>
using namespace std;
const int N=2e5+9;
int a[N],n; 
int work(){
	int x,ans;
	scanf("%d",&n);
	for(int i=0;i<=n+1;i++)a[i]=0; 
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		a[x]=i;	
	}
	ans=n\/2;
	\/\/1 2  8 9满座这样的条件不用动。
	\/\/从内层结构开始,看是否需要移动 4 5 6  a[4]<a[5]  a[5]<a[6]

	for(int i=n\/2;i>=1;i--){
		if(a[i]<a[i+1]&&a[n-i]<a[n-i+1]){
			ans--;
		}
		else break;
	} 
	return ans; 
	
	
}
int main(){
		int t;
	cin>>t;
	while(t--){
		cout<<work()<<endl;
	}
} 

D Fixed Prefix Permutations

逆向思维,找到一个数列的逆序列,转化为字符串的前缀匹配。利用tire树或者哈希完成。

\/*
 8 10
3 4 9 6 10 2 7 8 1 5
3 9 1 8 5 7 4 10 2 6
3 10 1 7 5 9 6 4 2 8
1 2 3 4 8 6 10 7 9 5
1 2 3 4 10 6 8 5 7 9
9 6 1 2 10 4 7 8 3 5
7 9 3 2 5 6 4 8 1 10
9 4 3 7 5 6 1 10 8 2
p*q=r: r[j]=q[p[j]]
期望得到:q[p[j]]=j
比如:a'*a3=10
j==1: q[3]=1, p1=3;  j=2,q[p[2]]=2,p[2]=9
	p[q[j]]=j
i    :1  2  3  4  5  6  7  8  9  10
a3  q:3  10 1  7  5  9  6  4  2  8
a3' p:3  9  1  8  5  7  4  10 6  2
那么找出a3的逆排列a'
	ai*a3即为ai与a3'的最大前缀,记为:f(ai,a3')。
	ans(ai)=max(f(ai*aj'))
	
算法步骤:贪心求出每一个aj',存入字典序
          对每个ai,查找其在字典序上的最大前缀。 
 
    	 
*\/ 
 
#include<bits\/stdc++.h>
using namespace std;
const int N=5e4+10,M=12;
int t,n,m,trie[800005][11],cnt=1;
int a[N][M];
void insert(int b[]){
	int p=0;
	int temp[M]={0};\/\/p[q[j]]=j
	for(int i=1;i<=m;i++)temp[b[i]]=i;
	for(int i=1;i<=m;i++){
		int v=temp[i];
		if(!trie[p][v])trie[p][v]=cnt++;
		p=trie[p][v];
	}
}
int ask(int b[]){
	int p=0,ans=0;
	for(int i=1;i<=m;i++){
		int v=b[i];
		if(trie[p][v]){
			ans++;
			p=trie[p][v];
		}else break;
	}
	return ans;
}
int main(){
	cin>>t;
	while(t--){
		cin>>n>>m;
		for(int i=0;i<cnt;i++)
			for(int j=0;j<=10;j++)
				trie[i][j]=0;
		cnt=1;
		
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++)scanf("%d",&a[i][j]);
			insert(a[i]);
		}
		for(int i=1;i<=n;i++){
			cout<<ask(a[i])<<" ";
		}
		printf("\n");
	}
}

第十四届蓝桥杯大赛软件赛省赛A组 C++

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2023-04-08 20:29:20

C:平方差

X=YY-ZZ,X=(Y+Z)(Y-Z)=T1T2

Y=(T1+T2)/2,Z=(T1-T2)/2,T1T2奇偶性相同;

x为奇数总是可以 X=1*X 若X为偶数,则两个因子都为偶数,看他是否为4的倍数。 分开两种情况讨论即可。

D更小的数

思路:逆序对总是可以的。23()32这样的带回文的也是可以的。统计完逆序再统计区间两端的回文有些麻烦。 但这样的区间是依赖内部区间的,从小区间到大区间。考虑区间dp

设置bool dp[i][j]为这个区间反转后是否为符合要求的区间。

枚举区间长度,枚举起点i,找到终点j dp[i][j] aiaj:=0;aiaj:=1 ai=aj:dp[i-1][j-1],实际复杂度O(N*N)

SD2021夏令营题单

题解 P1241 【括号序列】

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2018-07-05 15:50:15

写一堆If太麻烦了,我们用一个数组来转换匹配

#include <iostream>
#include <string.h>
#include <string>
#include <stack>
#include<cstdio>
using namespace std;
char s[202],b[202],tj[9]= {'>','}',']',')','0','(','[','}','<'};
int n,fh[250];
\/\/tj,用来匹配的数组,fh,符号,用来替换的数组 
void judge() {
	stack<int> st;
	int i,l,j=0;
	scanf("%s",s);
	l=strlen(s);
	fh['(']=-1;fh[')']=1;fh['[']=-2;fh[']']=2;fh['{']=-3;fh['}']=3;fh['<']=-4;fh['>']=4;
	for (i=0; i<l; i++) {
		char c=s[i];
		if(fh[c]<0) st.push(i);\/\/左括号入栈
		else {
			if(!st.empty()){
				int k=st.top();	
				if(fh[s[k]]+fh[c]==0)b[i]=b[k]=1,st.pop();\/\/左右括号匹配
			}
		}
	}
	for(int i=0; i<l; i++)
		if(b[i])cout<<s[i];
		else{
			int k=fh[s[i]];
			if(k<0)cout<<s[i]<<tj[4+k];
			else cout<<tj[4+k]<<s[i];
		}
}
int main() {
	judge();
}

题解 CF1369D 【TediousLee】

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2020-07-02 17:15:31

这个题目画图思考后当然是递归或者递推啦! 对于层数为n的树,根节点的三个子节点中,左右子树为n-2,中间子树为n-1; 所以初步递推为f(n)=f(n-1)+2*f(n-2); 这个代码写完后发现是错的,错在哪里呢?当根节点为3的倍数时候,根节点与其三个子节点可以染色形成一组claw。 递推的初值为: f[0]=f[1]=f[2]=0

因此递推的式子为:

f(n)=f(n-1)+2*f(n-2) n%3!=0

f(n)=f(n-1)+2*f(n-2)+4 n%3==0

参考代码:

#include<bits\/stdc++.h>
using namespace std;
const int N=2e6+9 ;
typedef long long ll;
const ll mod=1e9+7;
ll a[N],f[N],t,x,n;

int main() {
	cin>>t;
	for(int i=1;i<=t;i++){
		scanf("%lld",&a[i]) ;
		n=max(n,a[i]);
	}
	f[0]=f[1]=f[2]=0,f[3]=4;
	for(int i=4;i<=n;i++){
		f[i]=(f[i-1]+2*f[i-2]%mod)%mod;
		if(i%3==0)f[i]=(f[i]+4)%!mod;
	}
		
	for(int i=1;i<=t;i++)printf("%lld\n",f[a[i]]);

}

题目记录

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2020-09-10 17:16:22

Codeforces Round #665 (Div. 2)1401 C:贪心排序 D:树、数学,dfs E:数据结构:树状数组、线段树 F:数据结构:线段树

P5588 小猪佩奇爬树 树上的路径,暴力lca 树形dp?0(n) P3398 仓鼠找sugar 书上的路径有无交叉点 lca的灵活运用。 P1395 会议 树的重心

P1157 组合的输出-枚举子集

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-09-25 16:34:01

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;
int v[30];;
int n,r;

int main()
{
    scanf("%d%d",&n,&r);
    int num=0;
    for(int i=(1<<n)-1;i>0;i--)
    {
        int cnt=0;
        for(int j=n-1;j>=0;j--)
            if(i&(1<<j)){
            	v[cnt++]=n-j;
            	 
			} 
		if(cnt==r){
			for(int j=0;j<r;j++)
                printf("%3d",v[j]);
        cout<<endl;
			num++;
		}
    }
    
    return 0;
}

P1562 还是N皇后

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-09-25 16:36:10

#include<iostream>
#include<stdio.h>
#include<cmath>
using namespace std;
int n,a[15];
int shu,ans;
int lowbit(int x) {
	return x&-x;
}
void dfs(int h,int l,int r,int p) {
	if(h==shu) {
		ans++;
		return;
	}
	int x=h|l|r|a[p];
	x=(~x)&shu;
	while(x) {
		int pi=lowbit(x);
		dfs(h|pi,(l|pi)>>1,(r|pi)<<1,p+1);
		x-=pi;
	}
}
int main() {
	cin>>n;
	for(int i=1; i<=n; i++) {
		string s;
		cin>>s;
		for(int j=0; j<n; j++) {
			if(s[j]=='.')a[i]|=(1<<(n-j-1));
		}
	}
	shu=(1<<n)-1;
	dfs(0,0,0,1);
	cout<<ans;
	return 0;
}
共 90 篇博客