题目传送门
考场上打表搞了一个很奇怪的结论,化简后就是 a ∗ b − a − b a*b-a-b a∗b−a−b。具体证明现在还是不大会。
代码:
#include
#include
#include
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;
}
题目传送门
一般用一个栈模拟,细节比较多。没什么好说的。
考场上写的代码只会统计第一个循环。。。然而还是有80。
当时太紧张就写得很丑。
代码:
#include
#include
#include
#include
#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;
}
题目传送门
最短路+记忆化搜索
考场上用最短路优化一下就有60了。。。
先刷一遍反图最短路求出每个点到 n n n的最短路 d i s [ i ] dis[i] dis[i]。
记 f [ i ] [ j ] f[i][j] f[i][j]表示到第 i i i个点,超出最短路的路程 ≤ j \leq j ≤j的方案数。搜索的时候对每条边的转移 f [ i ] [ j ] = ∑ f [ v ] [ j − d ] f[i][j]=\sum f[v][j-d] f[i][j]=∑f[v][j−d]。其中 d = d i s [ v ] − d i s [ i ] + w d=dis[v]-dis[i]+w d=dis[v]−dis[i]+w。判0环的话就记录一下当前状态有没有在访问路径上即可。
代码:
#include
#include
#include
#include
#include
#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 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;
}
题目传送门
并查集/BFS都可以。本来会爆long long的但是出题人没有卡。判断的时候移个项就好了
代码:
#include
#include
#include
#include
#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=m) addedge(i,MAXN+1);
}
for (int i=1;i
题目传送门
状压DP
为什么我会觉得prim是对的!为什么我70分的暴力都不打!果然我好菜
我是不会告诉你我不知道怎么枚子集的
n=12就是状压的范围。据说标算 O ( 4 n ) O(4^n) O(4n)我不会啊,优化过的 O ( n 3 n ) O(n3^n) O(n3n)我也不会啊,我只会 O ( n 2 3 n ) O(n^23^n) O(n23n)啊不管了能过就行!
Orz写模拟退火的
f [ i ] [ j ] [ s ] f[i][j][s] f[i][j][s]表示以 i i i为根的子树中, i i i的深度的为 j j j,子树中的节点集合为 s s s的最小代价。那么有 f [ i ] [ j ] [ s ] = m i n { f [ k ] [ j + 1 ] [ s s ] + f [ i ] [ j ] [ s − s s ] + a [ i ] [ k ] } f[i][j][s]=min\{f[k][j+1][ss]+f[i][j][s-ss]+a[i][k]\} f[i][j][s]=min{f[k][j+1][ss]+f[i][j][s−ss]+a[i][k]},其中 s s ss ss是 s s s的子集, k k k为 s s ss ss内的一个点。时间复杂度为 O ( n 3 3 n ) O(n^33^n) O(n33n)。
把转移方程中与 s s s无关的提取出来,预处理 g [ i ] [ j ] [ s ] = m i n { f [ k ] [ j + 1 ] [ s ] + a [ i ] [ k ] } g[i][j][s]=min\{f[k][j+1][s]+a[i][k]\} g[i][j][s]=min{f[k][j+1][s]+a[i][k]},这样就是 O ( n 2 3 n ) O(n^23^n) O(n23n)的了。
代码:
#include
#include
#include
#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+1棵树,前n棵维护当前这行(除了最后一列),第n+1棵维护最后一列。每次操作的时候分操作的列是不是最后一列讨论一下就好了。
细节有点多,调了好久最后还是借鉴了一下题解。
代码:
#include
#include
#include
#include
#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;
}
UPD 2018.11.11 假的,要退役了