CSP-S模拟14
下发文件和题解
A. 莓良心(改:新题来源)
设 Li 的最大值为 maxl,Ri 的最小值为 minr.
如果 maxl 小于等于 minr,显然所有的点都可以放在同一个位置上,答案即为 0.
相反,如果大于,设 maxl 所在区间放到位置 A,minr 所在区间放到位置 B. 那么对于其它点 xi,满足 B ≤ xi ≤ A.
设中间点内部贡献为 s,那么:
ans = s + ∑ | xi − B | + ∑ | A − xi |.
要求和最小,A 就取到 minr、B 就取到 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;
}
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/16741408.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!