A. Anniversary Cake
随便挑两个点切掉就好了。
#include
using namespace std;
const int Maxn=200020;
typedef long long LL;
typedef pairpi;
pi a[2];
int main()
{
freopen("anniversary.in","r",stdin);
freopen("anniversary.out","w",stdout);
int w,h;
scanf("%d%d",&w,&h);
int x,y;
for(int i=0;i<2;i++){
scanf("%d%d",&x,&y);
a[i]=pi(x,y);
}
sort(a,a+2);
//puts("ok");
if(a[0].first==a[1].first){
printf("%d %d %d %d\n",0,a[0].second,w,a[1].second);
}
else{
printf("%d %d %d %d\n",a[0].first,0,a[1].first,h);
}
return 0;
}
B. Boys and Girls
分类讨论构造。
#include
using namespace std;
const int Maxn=105;
typedef long long LL;
typedef pairpi;
int n,x,y;
string rep;
void pt(int cnt,string s){
for(int i=0;i=4){
if(t1%4==0){
int cnt=t1/4;
pt(cnt-1,"BBGG");
pt(2+t2,"B");
pt(2+t3,"G");
return 1;
}
else{
if(!t2&&!t3)return 0;
if(t2){
pt(t2+1,"B");
pt(t3+2,"G");
for(int i=0;i=t3){
pt(t2-t3+1,"B");
pt(1,"G");
pt(t3,"BG");
}
else{
pt(t3-t2+1,"G");
pt(1,"B");
pt(t2,"GB");
}
return 1;
}
else
if(!t1){
if(t2!=t3)return 0;
if(t2+t3!=n)return 0;
for(int i=0;i>j&1)tmp[j]='G';
else tmp[j]='B';
}
if(go()){
puts("wa");
cout<
C. CodeCoder vs TopForces
将所有人按两种rating分开排序,相邻的之间连有向边,那么SCC缩点之后,剩下的图是个竞赛图,求出拓扑序之后前面所有的点都是可达的。
#include
#include
using namespace std;
const int N=500000;
int n,i,a[N],b[N],q[N];
int g[2][N],v[2][N],nxt[2][N],ed;
int vis[N],size[N],f[N],ans[N],sum,t;
inline bool cmpa(int x,int y){return a[x]
D. Digital Addition
从低位到高位DP即可。
#include
using namespace std;
const int Maxn=105;
typedef long long LL;
typedef pairpi;
pi a[2];
int occ[3][10]={{3,0,2,0,1,1,3,0,3,1},
{5,0,7,7,2,7,7,1,7,7}
,{3,3,1,3,3,2,2,3,3,3}
};
int has[10][10][10][3];
int s1[10][Maxn],s2[10][Maxn];
int n;
int num[Maxn][3];
int dp[Maxn][2][16];
int rep[3][Maxn];
bool debug;
struct Node{
int a,b,c;
Node(){}
Node(int a,int b,int c):a(a),b(b),c(c){}
}pre[Maxn][2][16],pe[Maxn][2][16];
int main()
{
freopen("digital.in","r",stdin);
freopen("digital.out","w",stdout);
for(int i=0;i<10;i++)
for(int j=0;j<10;j++)
for(int k=0;k<10;k++){
for(int ty=0;ty<3;ty++){
has[i][j][k][ty]=occ[ty][i]|(occ[ty][j]<<1)|(occ[ty][k]<<2);
}
}
while(scanf("%d",&n)!=EOF){
int t1=0,t2=0;
for(int i=0;i<9;i++){
if(i%2==0){
for(int j=0;j=0;i--)
for(int j=0;j<2;j++)
for(int mask=0;mask<16;mask++){
if(!dp[i+1][j][mask])continue;
//printf("i=%d j=%d mask=%d\n",i,j,mask);
for(int a=0;a<10;a++)
for(int b=0;b<10;b++)
for(int c=0;c<10;c++){
if(i==1&&j==0&&a==7&&b==4&&c==1)debug=1;
else debug=0;
if((a+b+j)%10!=c)continue;
int nj=(a+b+j)/10,nmask=has[a][b][c][0];
int t0=has[a][b][c][0];
int t1=has[a][b][c][1];
int t2=has[a][b][c][2]|mask;
//if(debug)printf("t0=%d t1=%d t2=%d\n",t0,t1,t2);
if((t1!=num[i][1])||(t2!=num[i][2]))continue;
dp[i][nj][nmask]=1;
pre[i][nj][nmask]=Node(i+1,j,mask);
pe[i][nj][nmask]=Node(a,b,c);
//if(debug)printf("i+1=%d %d %d\n",i+1,nj,nmask);
}
}
int cs=num[0][0];
if(!dp[0][0][cs]){puts("NO");}
else{
int curj=0,curmask=cs;
for(int i=0;i
E. Easy Reading
注意到$n\times m\leq 10^5$,那么有$\min(n,m)\leq\sqrt{10^5}$,不妨假设$n\leq m$,剩下的情况可以通过旋转来保证$n\leq m$。
枚举左端点,往右延伸右端点,维护经过的点的个数,直到找到第一个使得经过的点的个数不小于给定图案里点的个数的右端点为止。
这个过程可以通过two-pointer实现,同时维护目前框住矩形的上下左右边界,以及每一行的hash值,当点数相等、矩形边界相等时,暴力扫描每一行判断是否匹配即可。
时间复杂度$O(|S|\sqrt{nm})$。
#include
#include
#include
#include
F. Folding
按题意模拟即可。
#include
using namespace std ;
const int INF = 2e9 ;
int W , H , w , h ;
int get ( int x , int y ) {
if ( x == y ) return 0 ;
int t = 0 ;
while ( x > 2 * y ) x = ( x + 1 ) / 2 , ++ t ;
return t + 1 ;
}
void solve () {
int ans = INF ;
if ( W >= w && H >= h ) ans = min ( get ( W , w ) + get ( H , h ) , ans ) ;
if ( W >= h && H >= w ) ans = min ( get ( W , h ) + get ( H , w ) , ans ) ;
if ( ans == INF ) printf ( "-1\n" ) ;
else printf ( "%d\n" , ans ) ;
}
int main () {
freopen("folding.in","r",stdin);
freopen("folding.out","w",stdout);
while ( ~scanf ( "%d%d%d%d" , &W , &H , &w , &h ) ) solve () ;
return 0 ;
}
G. Gangsters in Central City
将根去掉,那么原树将分裂成若干子树,每个子树如果有强盗,那么就要割掉它们的lca,否则不需要割,线段树维护区间关键点的lca即可。
时间复杂度$O(m\log^2n)$。
#include
#include
using namespace std;
const int N=100010;
int n,m,i,x,g[N],v[N],nxt[N],ed;
int f[N],d[N],size[N],leaf[N],son[N],top[N];
int st[N],en[N],dfn,from[N];
int ans0,ans1,all;
bool vip[N];
char op[5];
int val[262150];
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
size[x]=1;
leaf[x]=g[x]==0;
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
f[v[i]]=x;
d[v[i]]=d[x]+1;
dfs(v[i]);
size[x]+=size[v[i]];
leaf[x]+=leaf[v[i]];
if(size[v[i]]>size[son[x]])son[x]=v[i];
}
}
void dfs2(int x,int y){
st[x]=++dfn;
top[x]=y;
if(son[x])dfs2(son[x],y);
for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
en[x]=dfn;
}
void dfs3(int x,int y){
from[x]=y;
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x])dfs3(v[i],y);
}
inline int lca(int x,int y){
for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]>1;
if(c<=mid)change(x<<1,a,mid,c,p);else change(x<<1|1,mid+1,b,c,p);
val[x]=merge(val[x<<1],val[x<<1|1]);
}
int ask(int x,int a,int b,int c,int d){
if(c<=a&&b<=d)return val[x];
int mid=(a+b)>>1,t=0;
if(c<=mid)t=ask(x<<1,a,mid,c,d);
if(d>mid)t=merge(t,ask(x<<1|1,mid+1,b,c,d));
return t;
}
inline void ins(int x){
if(vip[x])return;
vip[x]=1;
all++;
int l=st[from[x]],r=en[from[x]];
int z=ask(1,1,n,l,r);
if(z)ans0--,ans1-=leaf[z];
change(1,1,n,st[x],x);
z=ask(1,1,n,l,r);
if(z)ans0++,ans1+=leaf[z];
}
inline void del(int x){
if(!vip[x])return;
vip[x]=0;
all--;
int l=st[from[x]],r=en[from[x]];
int z=ask(1,1,n,l,r);
if(z)ans0--,ans1-=leaf[z];
change(1,1,n,st[x],0);
z=ask(1,1,n,l,r);
if(z)ans0++,ans1+=leaf[z];
}
int main(){
freopen("gangsters.in","r",stdin);
freopen("gangsters.out","w",stdout);
scanf("%d%d",&n,&m);
for(i=2;i<=n;i++)scanf("%d",&x),add(x,i);
dfs(1);
dfs2(1,1);
for(i=g[1];i;i=nxt[i])dfs3(v[i],v[i]);
while(m--){
scanf("%s%d",op,&x);
if(op[0]=='+')ins(x);
else del(x);
printf("%d %d\n",ans0,ans1-all);
}
return 0;
}
H. Hard Cuts
留坑。
I. Integral Polygons
预处理出前缀叉积和,然后将叉积以及点的坐标都模2,枚举右端点,暴力枚举左端点的坐标以及叉积值即可。
时间复杂度$O(n)$。
#include
using namespace std;
const int Maxn=200020;
typedef long long LL;
int n;
int cnt[2][2][2];
int x[Maxn],y[Maxn];
int main()
{
freopen("integral.in","r",stdin);
freopen("integral.out","w",stdout);
while(scanf("%d",&n)!=EOF){
int sum=0;
for(int i=0;i
J. Java2016
不断生成随机数取$\max$即可以几乎为$100%$的概率得到$1$,然后可以得到$2,4,8,16,32,64,128$,将$c$二进制拆分即可。
#include
int n,i,flag;
int main(){
freopen("java2016.in","r",stdin);
freopen("java2016.out","w",stdout);
scanf("%d",&n);
if(!n)return puts("?/?/?"),0;
puts("a=? max ?");
for(i=1;i<18;i++)printf("%c=%c max %c\n",'a'+i,'a'+i-1,'a'+i-1);
printf("%c=%c/%c\n",'a'+18,'a'+17,'a'+17);
for(i=19;i<26;i++)printf("%c=%c+%c\n",'a'+i,'a'+i-1,'a'+i-1);
for(i=0;i<8;i++)if(n>>i&1){
if(flag)putchar('+');
flag=1;
putchar(i+'a'+18);
}
return 0;
}
K. King’s Heir
按题意模拟即可。
#include
#include
using namespace std;
const int N=500000;
int death,n,i,now,ans,id;
int s[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int get(){
int d,m,y;
scanf("%d%d%d",&d,&m,&y);
int t=y*365+d+s[m-1];
return t;
}
int main(){
freopen("king.in","r",stdin);
freopen("king.out","w",stdout);
for(i=1;i<=12;i++)s[i]+=s[i-1];
death=get();
scanf("%d",&n);
ans=-1;
id=-1;
for(i=1;i<=n;i++){
now=get();
if(death-now>=365*18&&now>ans)ans=now,id=i;
}
printf("%d",id);
return 0;
}
总结:
- J题发现题读错之后集体放弃了思考,以致于过了E的情况下还只有9题,下次要注意。