返回上一页

CSP-S模拟14

下发文件和题解

A. 莓良心(改:新题来源

Li 的最大值为 maxlRi 的最小值为 minr.

如果 maxl 小于等于 minr,显然所有的点都可以放在同一个位置上,答案即为 0.

相反,如果大于,设 maxl 所在区间放到位置 Aminr 所在区间放到位置 B. 那么对于其它点 xi,满足 B ≤ xi ≤ A.

设中间点内部贡献为 s,那么:

ans = s + ∑ | xi − B | + ∑ | A − xi |.

要求和最小,A 就取到 minrB 就取到 maxl,那么:

ans = s + (n-1) × ( minr - maxl ) .

计算 s 的方法就是不断按照上面的过程递归计算,然后把已使用的值去掉.

归纳一下其实并不需要这么麻烦,只需要把 Li 从大到小排序,把 Ri 从小到大排序,然后就有了:

.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define sinline static inline
#define rll rg ll
#define maxn 300001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ll read()
{
	rll f=0,x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
sinline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,l[maxn],r[maxn],ans=0;
bool fl[maxn];
ll nowl,nowr;
int main()
{
	n=read();for(rll i=1;i<=n;i++) l[i]=read(),r[i]=read();
	sort(l+1,l+n+1);sort(r+1,r+n+1);
	if(l[n]<=r[1]) { puts("0"); return 0; }
	for(rll i=1;i<=n;i++) ans+=max(0ll,l[n-i+1]-r[i])*(n-(i<<1)+1);write(ans);
	return 0;
}

B. 尽梨了(改:新题来源

贺的. 原文

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define sinline static inline
#define rll rg ll
#define maxn 5001
#define mod 998244353
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ll read()
{
	rll f=0,x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();return f?-x:x;
}
sinline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,a[maxn],b[maxn],c[maxn],d[maxn],ans;
ll C[maxn][maxn],f[maxn],g[maxn],sum[maxn],sum2[maxn];
char s[maxn];
sinline bool cmp(rll x,rll y) { return x>y; }
int main()
{
	n=read(); C[0][0]=1; for(rll i=1;i<=n;i++) { C[i][0]=C[i][i]=1; for(rll j=1;j<i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod; }
	for(rll i=1;i<=n;i++) { scanf("%s",s+1); for(rll j=1;j<=n;j++) if(s[j]=='1') a[i]++,b[j]++; }
	for(rll k=1;k<=2;k++)
	{
		memset(c,0,sizeof(c)); memset(d,0,sizeof(d)); f[0]=1; sort(a+1,a+n+1,cmp);
		for(rll i=1;i<=n;i++) c[a[i]]++; for(rll i=1;i<=n;i++) sum[0]+=n-a[i];
		for(rll i=1;i<=n;i++) f[i]=C[c[a[i]]][++d[a[i]]],sum[i]=sum[i-1]-n+(a[i]<<1);
		swap(a,b); swap(sum,sum2); swap(f,g);
	}
	for(rll i=0;i<=n;i++) for(rll j=0;j<=n;j++) if(sum[i]+sum2[j]-i*j-(n-i)*(n-j)==n*n) ans=(ans+f[i]*g[j]%mod)%mod;
	write(ans);
	return 0;
}

C. 团不过

显然总方案数为 ( 2n - 1 ) × ( 2n - 2 ) × … × ( 2n - n ) .

正难则反. 异或和不为 0 的不好求,那就求为 0 的.

dp[i] 是前 i 位总异或和为 0 的方案数.

当前 i - 1 个数的异或和为 0 的时候,这一次异或后一定不为 0.

当前 i-2 个的异或和为 0,这两个数若要异或为 0 就一定需要相同,因此一定不为 0(赛时被这个迷惑住了,导致最终没有推出式子).

那么式子很好写了(设 p[i] 表示取了 i 个的总方案数):

dp[i] = p[i - 1] - dp[i - 1] - (i - 1) × (2n - i + 1) × dp[i - 2].

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define sinline static inline
#define rll rg ll
#define maxn 10000001
#define mod 1000000007
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ll read()
{
	rll f=0,x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
sinline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,mi;
ll p[maxn],dp[maxn];
sinline ll ksm(rll a,rll b) { rll ans=1; a%=mod; for(rll i=b;i;i>>=1) { if(i&1) ans=ans*a%mod; a=a*a%mod; } return ans; }
int main()
{
	n=read();if(n==1) { putchar('1');return 0; }
	mi=ksm(2,n);p[0]=1;for(rll i=1;i<=n;i++) p[i]=p[i-1]*(mi-i)%mod;// 总方案
	for(rll i=3;i<=n;i++) dp[i]=(p[i-1]-dp[i-1]+mod-(i-1)*(mi-i+1+mod)%mod*dp[i-2]%mod+mod)%mod;// 异或为0的方案
	write((p[n]-dp[n]+mod)%mod);
	return 0;
}

D. 七负我

最大团模板题.

可以用 Bron-Kerbosch 或者 meet in the middle 解决这类问题.

这里我用了前者. 这里是详细讲解

这是一个更板子的板子

统计答案的时候,因为是完全图,手模一下,设 ans 为其点数,答案即为:

.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define ld long double
#define rg register
#define sinline static inline
#define rll rg ll
#define maxn 201
#define pll pair<ll,ll>
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ll read()
{
	rll f=0,x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();return f?-x:x;
}
sinline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,m,x;
ld k,t,ans;
bool mp[maxn][maxn];
ll mx[maxn]/*第i个点之后能组成最大团大小*/,s[maxn][maxn]/*s[i][j]为第i层进行dfs所需要点的集合,即其中有可能是最大团之一的点*/;
sinline bool dfs(rll x/*集合大小*/,rll num/*层数*/)
{
	if(!x) return num>ans?ans=num,1:0;
	for(rll i=1,u,tot;i<=x;i++)
	{
		u=s[num][i]; tot=0; if(x-i+1+num<=ans||mx[u]+num<=ans) return 0;
		for(rll j=i+1;j<=x;j++) if(mp[u][s[num][j]]) s[num+1][++tot]=s[num][j];
		if(dfs(tot,num+1)) return 1;
	}
	return 0;
}
sinline ll solve()
{
	for(rll i=n,tot;i;i--)
	{
		tot=0; for(rll j=i+1;j<=n;j++) if(mp[i][j]) s[1][++tot]=j;
		dfs(tot,1); mx[i]=ans;
	}
	return ans;
}
int main()
{
	n=read();m=read();x=read();for(rll i=1,u,v;i<=m;i++) mp[v][u]=mp[u=read()][v=read()]=1;
	printf("%.6Lf",(ld)x*x/2/(ans=solve())*(ans-1));
	return 0;
}
posted @   1Liu  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示