A - Range Product
如果区间包含0就输出Zero,如果负数的个数是奇数个就输出Negative,否则输出Positive
#include<bits/stdc++.h>
using namespace std;
#define RI register int
int a,b;
int main()
{
scanf("%d%d",&a,&b);
if(a<=0&&b>=0) puts("Zero");
else if(a<0&&b<0&&(b-a+1)%2) puts("Negative");
else puts("Positive");
return 0;
}
B - Box and Ball
直接模拟。对于从x盒子里拿一个球到y盒子这一步,若x盒子里可能有红球,则y盒子里也有可能有红球了。但是若把x盒子拿空了,x盒子就不可能有红球了。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
int q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q;
}
const int N=100005;
int red[N],num[N],n,m,ans;
int main()
{
int x,y;
n=read(),m=read();
for(RI i=1;i<=n;++i) num[i]=1;
red[1]=1;
for(RI i=1;i<=m;++i) {
x=read(),y=read();
if(red[x]) red[y]=1;
--num[x],++num[y];
if(!num[x]) red[x]=0;
}
for(RI i=1;i<=n;++i) if(red[i]) ++ans;
printf("%d\n",ans);
return 0;
}
C - Knot Puzzle
考虑进行到只剩一个绳结,则两段绳子的长度和必须大于等于L,否则这个绳结没法解。所以找到整根绳子中长度和大于等于L的两段,将左边的绳结从左往右解开,右边的绳结从右往左解开,最后将这个绳结解开。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
int q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q;
}
const int N=100005;
int n,L,a[N];
void work(int x) {
puts("Possible");
for(RI i=1;i<x;++i) printf("%d\n",i);
for(RI i=n-1;i>x;--i) printf("%d\n",i);
printf("%d\n",x);
}
int main()
{
n=read(),L=read();
for(RI i=1;i<=n;++i) a[i]=read();
for(RI i=1;i<n;++i)
if(a[i]+a[i+1]>=L) {work(i);return 0;}
puts("Impossible");
return 0;
}
D - Stamp Rally
整体二分+按秩合并资兹删除操作的并查集。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
int q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q;
}
const int N=100005;
struct edge{int x,y;}e[N];
struct quesion{int x,y,z,id;}q[N],k1[N],k2[N];
int n,m,Q,top;
int ans[N],f[N],sz[N],d[N],s1[N],s2[N],tag[N];
int find(int x) {while(x!=f[x]) x=f[x];return x;}
void work(int l,int r,int ql,int qr) {
if(ql>qr) return;
if(l==r) {
for(RI i=ql;i<=qr;++i) ans[q[i].id]=l;
return;
}
int mid=(l+r)>>1,ktop=top,js1=0,js2=0;
for(RI i=l;i<=mid;++i) {
int r1=find(e[i].x),r2=find(e[i].y);
if(r1!=r2) {
if(d[r1]<d[r2]) swap(r1,r2);
++top,s1[top]=r1,s2[top]=r2;
f[r2]=r1,sz[r1]+=sz[r2];
if(d[r1]==d[r2]) ++d[r1],tag[top]=1;
else tag[top]=0;
}
}
for(RI i=ql;i<=qr;++i) {
int r1=find(q[i].x),r2=find(q[i].y),cango;
if(r1==r2) cango=sz[r1];
else cango=sz[r1]+sz[r2];
if(cango>=q[i].z) k1[++js1]=q[i];
else k2[++js2]=q[i];
}
for(RI i=1;i<=js1;++i) q[ql+i-1]=k1[i];
for(RI i=1;i<=js2;++i) q[ql+js1-1+i]=k2[i];
work(mid+1,r,ql+js1,qr);
while(top>ktop) {
f[s2[top]]=s2[top],sz[s1[top]]-=sz[s2[top]];
if(tag[top]) --d[s1[top]];
--top;
}
work(l,mid,ql,ql+js1-1);
}
int main()
{
n=read(),m=read();
for(RI i=1;i<=m;++i) e[i].x=read(),e[i].y=read();
Q=read();
for(RI i=1;i<=Q;++i)
q[i].x=read(),q[i].y=read(),q[i].z=read(),q[i].id=i;
for(RI i=1;i<=n;++i) f[i]=i,d[i]=sz[i]=1;
work(1,m,1,Q);
for(RI i=1;i<=Q;++i) printf("%d\n",ans[i]);
return 0;
}
E - Candy Piles
把糖果从大到小排序,然后看做一个不规则的棋盘,第 i i i列有 a i a_i ai个格子。从左下角的格子出发,每个人的操作是可以向上走一格或向右走一格,走到上面和右边都没有格子的地方就输了。
按博弈的思想,有两种状态,必胜态N和必败态P。所有上面和右边都没有格子的格子状态是P,其他格子(x,y)的状态和(x+1,y+1)状态相同。
这是因为,能走到P的格子状态是N,只能走到N的状态是P。如果(x+1,y+1)是P,则(x,y+1)和(x+1,y)都是N,则(x,y)必是P;如果(x+1,y+1)是N,则(x+1,y+2)和(x+2,y+1)中有一个是P,则(x,y+2)和(x+2,y)中有一个是N,则(x,y+1)和(x+1,y)中有一个是P,则(x,y)是N。
那么我们只要找到一个最大的没越界的格子(x,x),看一下它的上面和右边的状态,算出它的状态,它的状态就是(1,1)的状态。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
int q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q;
}
const int N=100005;
int n,a[N];
int cmp(int x,int y) {return x>y;}
int main()
{
n=read();
for(RI i=1;i<=n;++i) a[i]=read();
sort(a+1,a+1+n,cmp);
for(RI i=1;i<=n;++i)
if(i+1>a[i+1]) {
int j=i+1;while(a[j]==i) ++j;
int ans=(j-i-1)&1;
ans|=(a[i]-i)&1;
if(ans) puts("First");
else puts("Second");
return 0;
}
return 0;
}
F - Leftmost Ball
序列的任意一个后缀,第 n + 1 n+1 n+1种颜色的球的数量都不能超过其他颜色的颜色总数。
我们发现前 n n n种颜色都是等价的,所以先钦定一个颜色加入的顺序,最后再去乘一个 n ! n! n!
记 f ( i , j ) f(i,j) f(i,j)表示放了 i i i种(除第 n + 1 n+1 n+1种以外的)颜色, j j j个第 n + 1 n+1 n+1种颜色的球的序列方案数。考虑在这个序列的最前面放一个第 n + 1 n+1 n+1种颜色的球还是放一个新颜色的球,再把剩下的新颜色球插入到后面,这样进行转移。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
const int mod=1000000007,N=2005,M=4000005;
int n,K,f[N][N],fac[M],ni[M];
int qm(int x) {return x>=mod?x-mod:x;}
int ksm(int x,int y) {
int re=1;
for(;y;y>>=1,x=1LL*x*x%mod) if(y&1) re=1LL*re*x%mod;
return re;
}
void prework() {
fac[0]=1;for(RI i=1;i<=n*K;++i) fac[i]=1LL*fac[i-1]*i%mod;
ni[n*K]=ksm(fac[n*K],mod-2);
for(RI i=n*K-1;i>=0;--i) ni[i]=1LL*ni[i+1]*(i+1)%mod;
}
int C(int d,int u) {return 1LL*fac[d]*ni[u]%mod*ni[d-u]%mod;}
int main()
{
scanf("%d%d",&n,&K);
if(K==1) {puts("1");return 0;}
prework();--K;
f[0][0]=1;
for(RI i=1;i<=n;++i) {
for(RI j=0;j<=i;++j) {
if(j) f[i][j]=f[i][j-1];
f[i][j]=qm(f[i][j]+1LL*f[i-1][j]*C(i*K+j-1,K-1)%mod);
}
}
printf("%lld\n",1LL*f[n][n]*fac[n]%mod);
return 0;
}