冲刺国赛7.27
T1
把答案写成来就是 \(2\sum\limits_{i=1}^n ip_i-ip_i^2\) 要最大化这个东西
设 \(f_i(x)=ix-ix^2\) 求导变成 \(f'_i(x)=i-2ix\)
因为要最大化加和,所以每个函数的导数都是相等的,否则可以将变化率小的 \(x\) 变小,再将变化率大的 \(x\) 变大
设这个相等的值为 \(v\) ,于是 \(p_i=\frac{1}{2}-\frac{v}{2i}\)
因为 \(p_i\) 的加和为 \(1\) ,所以能解出 \(v\) ,但是这样 \(p_i\) 可能会是负数,所以让一段前缀为 \(0\) ,二分去查找那个位置
设这个位置为 \(be\) 那么 \(v=\frac{n-be-1}{s_n-s_{be-1}}\) 其中 \(s_i\) 为 \(\frac{1}{i}\) 的前缀和
然后再检验一下是否有负数,就能 \(O(1)\) 计算出答案了
Code
#include<bits/stdc++.h>
#define int long long
#define double long double
#define inf 0x3f3f3f3f3f3f3f3f
#define meow(args...) fprintf(stderr,args)
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int T,n;
double s[1000010];
inline void solve(){
n=read();
int l=1,r=n,be;double res=1;
while(l<=r){
int mid=(l+r)>>1;
double v=1.0L*(n-mid-1)/(s[n]-s[mid-1]);
if(v<=1.0L*mid) r=mid-1,res=v,be=mid;else l=mid+1;
}
printf("%.8Lf\n",res-res/2.0L*(n-be+1)+1.0L*(be+n)*(n-be+1)/4.0L);
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("sample.in","r",stdin);
freopen("sample.out","w",stdout);
for(int i=1;i<=1000000;i++) s[i]=s[i-1]+1.0L/i;
T=read();while(T--) solve();
return 0;
}
T2
首先给矩阵行差分一下,再列差分一下
发现只在四个位置修改了,分别是 \((l,l)+1,(l,r+1)-1,(r+1,l)-1,(r+1,r+1)+1\)
发现这跟矩阵树的基尔霍夫矩阵很像,于是我们可以直接求原图的生成树个数
考虑到 \(m\leq n+300\) 所以将一度点和二度点缩起来变成一条边,记录下来选择的和不选择的方案数
一度点可以直接删除,缩二度点时,直接向两边延伸,找到所在的链或者环
链的话直接新连一条边,选择的方案数为 \(1\) ,不选的方案数为链长加一
环的话直接给答案乘上环长
最后再用剩下的点再用行列式求
Code
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define inf 0x3f3f3f3f3f3f3f3f
#define meow(args...) fprintf(stderr,args)
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,m,und=1,pe,base=1,p,S,T;
int a[610][610],deg[500010],id[500010],idx;
int head[500010],ver[1000010],to[1000010],tot=1;
int fa[500010];
struct E{int x,y,v;}e[500010];
queue<int>q;
bool vis[500010];
int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
inline void merge(int x,int y){
x=getfa(x),y=getfa(y);
if(x==y) return ;fa[x]=y;
}
inline void add(int x,int y){ver[++tot]=y;to[tot]=head[x];head[x]=tot;}
inline int qpow(int x,int k){
int res=1,base=x;
while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
return res;
}
inline int det(int n){
int res=1;
for(int i=1,inv;i<=n;i++){
for(int j=i+1;j<=n&&!a[i][i];j++) if(a[j][i]) swap(a[i],a[j]),res=-res;
if(!a[i][i]) return 0;inv=qpow(a[i][i],mod-2);
for(int j=i+1,t;j<=n;j++){
t=a[j][i]*inv%mod;
for(int k=i;k<=n;k++) a[j][k]=(a[j][k]-a[i][k]*t%mod+mod)%mod;
}
}
for(int i=1;i<=n;i++) res=res*a[i][i]%mod;
return (res+mod)%mod;
}
void dfs(int x){
if(deg[x]!=2) return S?T=x:S=x,void();vis[x]=1;p++;
for(int i=head[x],y;i;i=to[i]) if(!vis[y=ver[i]]) dfs(y);
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("det.in","r",stdin);
freopen("det.out","w",stdout);
n=read()+1,m=read();
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1,l,r;i<=m;i++){
l=read(),r=read()+1;
deg[l]++,deg[r]++,add(l,r),add(r,l);
merge(l,r);
}
for(int i=1;i<=n;i++) if(getfa(i)!=getfa(1)) puts("0"),exit(0);
for(int i=1;i<=n;i++) if(deg[i]==1) q.push(i);
while(!q.empty()){
int x=q.front();q.pop();vis[x]=1;
for(int i=head[x],y;i;i=to[i]) if(!vis[y=ver[i]]) if(--deg[y]==1) q.push(y);
}
for(int i=1;i<=n;i++) if(deg[i]==2&&!vis[i]){
p=0,S=0,T=0;dfs(i);
if(!T) base=base*p%mod;else e[++pe]=(E){S,T,p+1};
}
for(int i=1;i<=n;i++) if(!vis[i]) id[i]=++idx;
for(int i=2,x,y;i<=tot;i+=2){
x=ver[i],y=ver[i^1];if(vis[x]||vis[y]) continue;
x=id[x],y=id[y];
(a[x][x]+=1)%=mod,(a[y][y]+=1)%=mod;
(a[x][y]+=mod-1)%=mod,(a[y][x]+=mod-1)%=mod;
}
for(int i=1;i<=pe;i++) und=und*e[i].v%mod;
for(int i=1,x,y,v;i<=pe;i++){
x=e[i].x,y=e[i].y,v=qpow(e[i].v,mod-2);
x=id[x],y=id[y];
(a[x][x]+=v)%=mod,(a[y][y]+=v)%=mod;
(a[x][y]+=mod-v)%=mod,(a[y][x]+=mod-v)%=mod;
}
printf("%lld\n",det(idx-1)*base%mod*und%mod);
return 0;
}
T3
如果这一列只有一张卡,那么就可以决定所在的行是否需要翻转
如果有两张以上那么就可以求出至多一张正面向上,再将所有的都翻转来得到至少一张正面向上
发现至多一张正面向上的情况可以直接用 \(2-sat\) 来做
该列某卡片正面向上 \(\rightarrow\) 该列其他卡片正面向下,连边时前后缀优化一下
每行一个变量表示是否翻转
因为某些众所周知的原因,退火也能通过,所以没写码