Day1
T1 小凯的疑惑
考场上打表搞了一个很奇怪的结论,化简后就是 。具体证明现在还是不大会。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
LL a,b;
int main(){
scanf("%lld%lld",&a,&b);
if (a>b) swap(a,b);
if (a==1){
printf("0\n");
return 0;
}
if (a==2){
printf("%lld\n",b-2);
fclose(stdin);
fclose(stdout);
return 0;
}
LL ans=(4+(a-3)*2+4)*(a-2)/2+1;
ans+=(b-a-1)*(a-1);
printf("%lld\n",ans);
return 0;
}
T2 时间复杂度
一般用一个栈模拟,细节比较多。没什么好说的。
考场上写的代码只会统计第一个循环。。。然而还是有80。
当时太紧张就写得很丑。
代码:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 100
using namespace std;
struct Orz{
char c;
bool f;
}stack[MAXN+5];
int top,t,l,cmp,a[MAXN+5],ma;
int f;
char s[MAXN+5],sc[MAXN+5],sx[MAXN+5],sy[MAXN+5];
int main(){
scanf("%d",&t);
while (t--){
memset(a,0,sizeof(a));
f=0; top=0; cmp=0; ma=0;
scanf("%d%s",&l,s);
if (s[2]=='n') f=1;
for (int i=0;s[i];i++)
if (s[i]>='0'&&s[i]<='9')
cmp=cmp*10+s[i]-48;
int num=0;
bool flag=false,fa=false,fl=false; if (l&1) flag=true;
for (int i=1;i<=l;i++){
int ff=0; char ss[2];
scanf("%s",ss);
ff=ss[0];
if (ff=='F'){
int c,x=0,y=0;
scanf("%s%s%s",sc,sx,sy);
c=sc[0];
for (int j=0;sx[j];j++)
if (sx[j]>='0'&&sx[j]<='9')
x=x*10+sx[j]-48;
for (int j=0;sy[j];j++)
if (sy[j]>='0'&&sy[j]<='9')
y=y*10+sy[j]-48;
if (sx[0]=='n') x='n';
if (sy[0]=='n') y='n';
if (flag) continue;
if (a[c-'a']){ flag=true; continue; }
if (x=='n'&&y!='n') fl=true;
if (x!='n'&&y!='n'&&x>y) fl=true;
if (x!='n'&&y=='n') num++;
if (x!='n'&&y=='n'&&(!fl)) fa=true,ma=max(ma,num);
a[c-'a']++;
Orz p; p.c=c;
if (x!='n'&&y=='n') p.f=true;
else p.f=false;
stack[++top]=p;
}
else{
if (!top) { flag=true; continue; }
if (stack[top].f) num--;
a[stack[top--].c-'a']--;
if (!top) fl=false;
}
}
if (top) flag=true;
if (flag){
printf("ERR\n");
continue;
}
if ((fa&&(f==0))||(ma!=cmp&&(f==1))){
printf("No\n");
continue;
}
printf("Yes\n");
}
return 0;
}
T3 逛公园
最短路+记忆化搜索
考场上用最短路优化一下就有60了。。。
先刷一遍反图最短路求出每个点到 的最短路 。
记 表示到第 个点,超出最短路的路程 的方案数。搜索的时候对每条边的转移 。其中 。判0环的话就记录一下当前状态有没有在访问路径上即可。
代码:
#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define F inline
using namespace std;
struct P{ int x,d; };
struct edge{ int nxt,to,d; }ed[N<<2];
int n,m,k,p,K,d[N],h1[N],h2[N],f[N][55];
priority_queue<P> q; bool v[N][55];
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
return l==r?EOF:*l++;
}
F int _read(){
int x=0; char ch=readc();
while (!isdigit(ch)) ch=readc();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x;
}
#define add(h,x,y,z) ed[++k]=(edge){h[x],y,z},h[x]=k
F bool operator <(P a,P b){ return a.d>b.d; }
F void Dij(){
while (!q.empty()) q.pop();
for (q.push((P){n,d[n]=0});!q.empty();q.pop()){
int x; if (q.top().d>d[x=q.top().x]) continue;
for (int i=h2[x],v;i;i=ed[i].nxt)
if (d[v=ed[i].to]>d[x]+ed[i].d)
d[v]=d[x]+ed[i].d,q.push((P){v,d[v]});
}
}
int dfs(int x,int k){
if (v[x][k]) return -1; if (f[x][k]) return f[x][k];
v[x][k]=true,f[x][k]+=(x==n);
for (int i=h1[x],v,w;i;i=ed[i].nxt)
if ((w=d[v=ed[i].to]-d[x]+ed[i].d)<=k)
if (dfs(v,k-w)==-1) return -1;
else (f[x][k]+=f[v][k-w])%=p;
return v[x][k]=false,f[x][k];
}
int main(){
for (int t=_read();t;t--){
n=_read(),m=_read(),K=_read(),p=_read(),k=0;
for (int i=1;i<=n;i++) h1[i]=h2[i]=0,d[i]=1e9;
for (int i=1;i<=n;i++)
for (int j=0;j<=K;j++) f[i][j]=v[i][j]=0;
for (int i=1,x,y,z;i<=m;i++){
x=_read(),y=_read(),z=_read();
add(h1,x,y,z),add(h2,y,x,z);
}
Dij(),printf("%d\n",dfs(1,K));
}
return 0;
}
Day2
T1 奶酪
并查集/BFS都可以。本来会爆long long的但是出题人没有卡。判断的时候移个项就好了
代码:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 1000
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long LL;
struct edge{
int next,to;
}ed[MAXN*MAXN*6+5];
struct node{
LL x,y,z;
}a[MAXN*2+5];
int t,n,k;
LL m,r;
int h[MAXN*2+5],que[MAXN*2+5];
bool f[MAXN*2+5];
void addedge(int x,int y){
ed[++k].next=h[x]; ed[k].to=y; h[x]=k;
}
LL calc(node a,node b){
return sqr(a.x-b.x)+sqr(a.y-b.y)+sqr(a.z-b.z);
}
bool bfs(int s,int t){
memset(f,false,sizeof(f));
int r=0,w=1; que[1]=s; f[s]=true;
while (r<w){
int x=que[++r];
for (int i=h[x];i;i=ed[i].next)
if (!f[ed[i].to]){
que[++w]=ed[i].to;
f[ed[i].to]=true;
}
}
return f[t];
}
int main(){
scanf("%d",&t);
while (t--){
memset(h,0,sizeof(h)); k=0;
scanf("%d%lld%lld",&n,&m,&r);
for (int i=1;i<=n;i++){
scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].z);
if (a[i].z<=r) addedge(MAXN+2,i);
if (a[i].z+r>=m) addedge(i,MAXN+1);
}
for (int i=1;i<n;i++)
for (int j=i+1;j<=n;j++)
if (calc(a[i],a[j])<=sqr(r*2))
addedge(i,j),addedge(j,i);
if (bfs(MAXN+2,MAXN+1)) printf("Yes\n");
else printf("No\n");
}
return 0;
}
T2 宝藏
状压DP
为什么我会觉得prim是对的!为什么我70分的暴力都不打!果然我好菜
我是不会告诉你我不知道怎么枚子集的
n=12就是状压的范围。据说标算
我不会啊,优化过的
我也不会啊,我只会
啊不管了能过就行!
Orz写模拟退火的
表示以 为根的子树中, 的深度的为 ,子树中的节点集合为 的最小代价。那么有 ,其中 是 的子集, 为 内的一个点。时间复杂度为 。
把转移方程中与 无关的提取出来,预处理 ,这样就是 的了。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 15
#define M (1<<12)+1
using namespace std;
int n,m,ans=1e9,a[N][N],f[N][N][M],g[N][N][M];
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++){
a[i][j]=1e9;
for (int s=1;s<1<<n;s++)
if (s!=1<<i-1) f[i][j][s]=g[i][j][s]=1e9;
}
for (int i=1,x,y,z;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),a[x][y]=a[y][x]=min(a[x][y],z);
for (int j=n-1;j;j--)
for (int i=1;i<=n;i++)
for (int s=1;s<1<<n;s++){
for (int k=1;k<=n;k++)
if (((1<<k-1)&s)&&a[i][k]!=1e9)
g[i][j][s]=min(g[i][j][s],f[k][j+1][s]+a[i][k]*j);
for (int ss=s&s-1;ss;ss=ss-1&s)
f[i][j][s]=min(f[i][j][s],f[i][j][s^ss]+g[i][j][ss]);
}
for (int i=1;i<=n;i++) ans=min(ans,f[i][1][(1<<n)-1]);
return printf("%d\n",ans),0;
}
T3 列队
线段树动态开点
去年不会动态开点啊。。。
建n+1棵树,前n棵维护当前这行(除了最后一列),第n+1棵维护最后一列。每次操作的时候分操作的列是不是最后一列讨论一下就好了。
细节有点多,调了好久最后还是借鉴了一下题解。
代码:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 300005
#define F inline
using namespace std;
typedef long long LL;
struct tree{ int ls,rs,sz; LL x; }t[N<<6];
int n,m,q,mx,nd,rt[N],p[N]; LL ans,tmp;
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
return l==r?EOF:*l++;
}
F int _read(){
int x=0; char ch=readc();
while (!isdigit(ch)) ch=readc();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x;
}
F void writec(LL x){ if (x>9) writec(x/10); putchar(x%10+48); }
#define pd(l,r,f) (f==n+1?max(min(r,n)-l+1,0):max(min(r+1,m)-l,0))
F void nsrt(int &x,int l,int r,int p,LL w,int f){
if (!x) t[x=++nd].sz=pd(l,r,f); int mid=l+r>>1;
t[x].sz++; if (l==r) return void(t[x].x=w);
if (p<=mid) nsrt(t[x].ls,l,mid,p,w,f);
else nsrt(t[x].rs,mid+1,r,p,w,f);
}
F LL srch(int &x,int l,int r,int w,int f){
if (!x) t[x=++nd].sz=pd(l,r,f); int mid=l+r>>1,p; t[x].sz--;
if (l==r) return t[x].x?t[x].x:t[x].x=(f<=n?1ll*(f-1)*m+l:1ll*l*m);
if (w<=(p=t[x].ls?t[t[x].ls].sz:mid-l+1))
return srch(t[x].ls,l,mid,w,f);
else return srch(t[x].rs,mid+1,r,w-p,f);
}
F LL calc(int x,int y){
LL ans,tmp=srch(rt[n+1],1,mx,x,n+1);
ans=y!=m?srch(rt[x],1,mx,y,x):tmp;
if (y!=m) nsrt(rt[x],1,mx,++p[x],tmp,x);
return nsrt(rt[n+1],1,mx,++p[n+1],ans,n+1),ans;
}
int main(){
n=_read(),m=_read(),q=_read(),mx=max(n,m)+q;
for (int i=1;i<=n+1;i++) p[i]=(i==n+1?n:m-1);
for (int x,y;q;q--) x=_read(),y=_read(),writec(calc(x,y)),puts("");
return 0;
}