周六超多比赛,为了上分还是只打了cf。。本来想上橙的。。甚至第一次赛前打好了各种模板。。。
被hack到心态崩了
很显然我们记r[x]表示时刻x的任意一个bus,跑一个2e5*n的暴力就可以了
挂了是因为只跑了1e5,怀疑人生
#include
#include
#include
#include
#include
#include
#include
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
#define copy(x,t) memcpy(x,t,sizeof(x))
#define fi first
#define se second
typedef std:: pair <int,int> pair;
typedef long long LL;
const int N=200005;
int v[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int main(void) {
int n=read(),t=read();
rep(i,1,n) {
int s=read(),d=read();
for (int j=s;j<=2e5;j+=d) v[j]=i;
}
rep(i,t,2e5) if (v[i]) {
printf("%d\n", v[i]);
return 0;
}
return 0;
}
没啥好说的,f[i,j]=min(a[i],b[j])
#include
#include
#include
#include
#include
#include
#include
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
#define copy(x,t) memcpy(x,t,sizeof(x))
#define fi first
#define se second
typedef std:: pair <int,int> pair;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int N=205;
int a[N],b[N],c[N][N],d[N][N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int main(void) {
int n=read(),m=read(),h=read();
rep(i,1,m) a[i]=read();
rep(i,1,n) b[i]=read();
rep(i,1,n) rep(j,1,m) c[i][j]=read();
rep(i,1,n) rep(j,1,m) {
if (!c[i][j]) continue;
d[i][j]=std:: min(b[i],a[j]);
}
rep(i,1,n) {
rep(j,1,m) {
printf("%d ", d[i][j]);
} puts("");
}
return 0;
}
首先我们可以算出剩余多少个左括号、右括号。一个比较显然的贪心就是我们先放左括号,再放右括号肯定不会更劣。
然后考虑怎么符合那个任意前缀不合法的情况,可以发现我们只需要保证前缀和>=1就可以了,那么特判一下什么时候放右括号就可以了。
这个挂了是因为没有最后再判一次整个序列是否合法。。
#include
#include
#include
#include
#include
#include
#include
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
#define copy(x,t) memcpy(x,t,sizeof(x))
#define fi first
#define se second
typedef std:: pair <int,int> pair;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int N=500005;
char s[N],p[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int main(void) {
int n; scanf("%d",&n);
if (n&1) return 0&puts(":(");
scanf("%s",s+1);
int l=0,r=0;
rep(i,1,n) {
if (s[i]=='(') l++;
else if (s[i]==')') r++;
}
int L=n/2-l,R=n/2-r;
rep(i,1,n) {
if (s[i]=='?') {
if (L) L--,p[i]='(';
else R--,p[i]=')';
} else p[i]=s[i];
}
l=r=0;
rep(i,1,n) {
if (p[i]=='(') l++;
else r++;
if (r>l||(r==l&&i<n)) return 0&puts(":(");
}
if (l!=r) return 0&puts(":(");
rep(i,1,n) putchar(p[i]);
return 0;
}
做的时候一直想着怎么变成01问题,然后掉二分答案的坑里面了。。
正解是这样的。我们设f[x]表示x的权值在x为根的叶子里面的排名,通过一些感受可以发现这个排名实际上是固定的。
那么对于max节点就继承排名最小的儿子,min节点就是儿子排名的和了
#include
#include
#include
#include
#include
#include
#include
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
#define copy(x,t) memcpy(x,t,sizeof(x))
#define fi first
#define se second
typedef std:: pair <int,int> pair;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int N=500005;
struct edge {int y,next;} e[N];
int f[N],op[N],ls[N],edCnt,cnt;
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
}
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void dfs(int x) {
int mx=INF,mn=0;
for (int i=ls[x];i;i=e[i].next) {
dfs(e[i].y);
mx=std:: min(mx,f[e[i].y]);
mn+=f[e[i].y];
}
if (!ls[x]) return (void) (cnt+=(f[x]=1));
(!op[x])?(f[x]=mn):(f[x]=mx);
}
int main(void) {
int n=read();
rep(i,1,n) op[i]=read();
rep(i,2,n) add_edge(read(),i);
dfs(1);
printf("%d\n", cnt-f[1]+1);
return 0;
}
首先观察2019和n的范围,这提示我们答案大概是扫一行扫一列然后做一些剩余操作这样子
考虑蛇的端点有什么性质,那就是头和尾所在格子度数恰好为1,其余蛇身所在格子都恰好为2
于是我们可以通过询问n整行来找到头尾所在的行,询问n整列来找到头尾所在的列,当头尾行列均不相同的时候这样是询问恰好2n次的
考虑到有头尾在同一行的情况,这时候我们再扫一次找到头尾所各自在的列,然后在这两列上二分即可。同一列的情况同理。
这样询问次数恰好是2n+2logn的,也就是最坏2020次。怎么办呢?我们只需要扫n-1行就可以确定头尾各自的行,列同理。那么就是最坏2018次了
据说还有随机化询问行和列的骚操作,这个就非常牛逼了。。
#include
#include
#include
#include
#include
#include
#include
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
#define copy(x,t) memcpy(x,t,sizeof(x))
#define fi first
#define se second
typedef std:: pair <int,int> pair;
typedef long double ld;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int MOD=1e9+7;
const int ny2=(MOD+1)/2;
const int N=2000005;
const ld pi=acos(-1);
const ld e=exp(1);
const ld eps=1e-8;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int ask(int x1,int y1,int x2,int y2) {
printf("? %d %d %d %d\n", x1,y1,x2,y2),fflush(stdout);
int x; scanf("%d",&x);
return x;
}
int main(void) {
int n; scanf("%d",&n);
int rx1=-1,rx2=-1,ry1=-1,ry2=-1;
rep(i,1,n-1) if (ask(1,i,n,i)&1) {
if (ry1==-1) ry1=i;
else {ry2=i; break;}
}
if (ry1>0&&ry2==-1) ry2=n;
if (ry1==-1) {
rep(i,1,n-1) if (ask(i,1,i,n)&1) {
if (rx1==-1) rx1=i;
else {rx2=i; break;}
}
if (rx1>0&&rx2==-1) rx2=n;
int pos1,pos2;
for (int l=1,r=n;l<=r;) {
int mid=(l+r)>>1;
if (ask(rx1,1,rx1,mid)&1) {
r=mid-1,ry1=mid;
} else l=mid+1;
}
for (int l=1,r=n;l<=r;) {
int mid=(l+r)>>1;
if (ask(rx2,1,rx2,mid)&1) {
r=mid-1,ry2=mid;
} else l=mid+1;
}
} else {
int pos1,pos2;
for (int l=1,r=n;l<=r;) {
int mid=(l+r)>>1;
if (ask(1,ry1,mid,ry1)&1) {
r=mid-1,rx1=mid;
} else l=mid+1;
}
for (int l=1,r=n;l<=r;) {
int mid=(l+r)>>1;
if (ask(1,ry2,mid,ry2)&1) {
r=mid-1,rx2=mid;
} else l=mid+1;
}
}
printf("! %d %d %d %d\n", rx1,ry1,rx2,ry2),fflush(stdout);
return 0;
}
考虑把长度为l的线段映射到长度为1的线段上,取出2n+1个端点来组成n个相邻区间。答案就是被覆盖至少k次区间的期望数量*每个区间的期望长度
考虑怎么求被覆盖至少k次区间的数量,我们可以把一段区间视为一对左右匹配的左右括号。设f[i,j]表示前i个端点,还有j个端点没有匹配右端点的方案数,转移的话讨论一下i这个位置放左括号还是右括号就可以了。
然后我们枚举一个分界点i,覆盖次数j,合并两端造成的贡献就是f[i,j]*f[n*2,j]*j!,也就是前半段方案*后半段方案,而j对括号可以任意匹配所以还要一个阶乘。
#include
#include
#include
#include
#include
#include
#include
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
#define copy(x,t) memcpy(x,t,sizeof(x))
#define fi first
#define se second
typedef std:: pair <int,int> pair;
typedef long double ld;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int MOD=998244353;
const int ny2=(MOD+1)/2;
const int N=4005;
const ld pi=acos(-1);
const ld e=exp(1);
const ld eps=1e-8;
LL fac[N],f[N][N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void upd(LL &x,LL v) {
x+=v,(x>=MOD)?(x-=MOD):0;
}
LL ksm(LL x,LL dep) {
LL res=1;
for (;dep;dep>>=1,x=x*x%MOD) {
(dep&1)?(res=res*x%MOD):0;
}
return res;
}
int main(void) {
fac[0]=fac[1]=1;
rep(i,2,N-1) fac[i]=fac[i-1]*i%MOD;
int n=read(),k=read(),l=read();
f[1][1]=1;
rep(i,1,n*2) rep(j,0,std:: min(i,n)) {
if (!f[i][j]) continue;
upd(f[i+1][j+1],f[i][j]);
if (j) upd(f[i+1][j-1],f[i][j]*j%MOD);
}
LL ans=0;
rep(i,1,n*2) rep(j,k,std:: min(i,n)) {
upd(ans,f[i][j]*f[n*2-i][j]%MOD*fac[j]%MOD);
}
ans=ans*ksm(f[n*2][0],MOD-2)%MOD;
ans=ans*l%MOD*ksm(n*2+1,MOD-2)%MOD;
printf("%lld\n", ans);
return 0;
}