小凯的疑惑
下面没有证明,只有结论
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<queue>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
#define ll long long
#define re register
#define file(a) freopen(a".in",,"r",stdin);freopen(a".out","w",stdout)
inline int gi(){
int f=1,sum=0;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return f*sum;
}
int a,b;
int main(){
a=gi();b=gi();
printf("%lld
",1ll*a*b-a-b);
return 0;
}
时间复杂度
没什么好说的,大模拟即可,而且没有细节.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define re register
#define ll long long
inline int gi(){
int f=1,sum=0;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return f*sum;
}
const int N=110;
char Time[110];int bl[N],Flag[N],top,jz[N],A[N],B[N],Goto[N],id[N],from[N],into[N];
int gettime();
char get();
char getFE();
int main(){
int T=gi();
while(T--){
int L=gi();scanf("%s",Time+1);
int t=gettime();int flag=1;top=0;
memset(Flag,0,sizeof(Flag));
for(int i=1;i<=L;i++){
char ch=getFE();
if(ch=='E'){jz[i]=0;if(!top)flag=0;else{Flag[bl[top]]=0;Goto[id[top]]=i;from[i]=id[top];top--;}continue;}
bl[++top]=get()-'a';id[top]=i;if(Flag[bl[top]])flag=0;Flag[bl[top]]=1;
ch=getchar();int x=0,y=0;
while((ch<'0' || ch>'9') && ch!='n')ch=getchar();
if(ch=='n')x=101;
else while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
ch=getchar();
while((ch<'0' || ch>'9') && ch!='n')ch=getchar();
if(ch=='n')y=101;
else while(ch>='0' && ch<='9'){y=y*10+ch-'0';ch=getchar();}
jz[i]=1;A[i]=x;B[i]=y;
}
if(top)flag=0;
if(!flag){puts("ERR");continue;}
int Mx=0,now=0;
for(int i=1;i<=L;i++){
if(jz[i]){
if(A[i]>B[i]){i=Goto[i];continue;}
if(B[i]<101 || A[i]==101)continue;
now++;into[i]=1;
}
else
if(into[from[i]]){into[from[i]]=0;now--;}
Mx=max(Mx,now);
}
if(Mx==t)puts("Yes");
else puts("No");
}
return 0;
}
char getFE(){
char ch=getchar();
while(ch!='F' && ch!='E')ch=getchar();
return ch;
}
int gettime(){
if(Time[3]=='1')return 0;
int ret=0,pos=5;
while(Time[pos]>='0' && Time[pos]<='9'){ret=ret*10+Time[pos]-'0';pos++;}
return ret;
}
char get(){
char ch=getchar();
while(ch<'a' || ch>'z')ch=getchar();
return ch;
}
逛公园
看到(k)的范围不大,想一下(dp).
令(dp_{i,j})表示到了(i)号点,与标准最短路的差为(j)的方案,记忆化搜索即可.运用一条路径更新的时候应该是要求反图的最短路.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define re register
#define ll long long
inline int gi(){
int f=1,sum=0;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return f*sum;
}
typedef pair<int,int> pii;
priority_queue<pii,vector<pii>,greater<pii> >q;
#define mp make_pair
const int N=200010;
int dis[N],vis[N],dp[N][60],n,front[N],cnt,m,p,k,Vis[N][60];
struct node{int to,nxt,w;}e[N<<1];
void Add(int u,int v,int w){e[++cnt]=(node){v,front[u],w};front[u]=cnt;}
void dijkstra(){
memset(dis,63,sizeof(dis));dis[n]=0;memset(vis,0,sizeof(vis));
q.push(mp(0,n));
while(!q.empty()){
int u=q.top().second;q.pop();
if(vis[u])continue;vis[u]=1;
for(int i=front[u];i;i=e[i].nxt)
if(i%2==0){
int v=e[i].to;
if(dis[v]>dis[u]+e[i].w){dis[v]=dis[u]+e[i].w;q.push(mp(dis[v],v));}
}
}
}
int flag,Time;
int dfs(int u,int K){
if(Vis[u][K]==Time){flag=1;return 0;}
if(~dp[u][K])return dp[u][K];
Vis[u][K]=Time;int sum=0;
for(int i=front[u];i;i=e[i].nxt)
if(i&1){
int v=e[i].to,kk=K-(dis[v]-dis[u]+e[i].w);
if(kk<0 || kk>k)continue;
sum=(sum+dfs(v,kk))%p;
if(flag)return 0;
}
Vis[u][K]=Time-1;
if(u==n && !K)sum=1;
return dp[u][K]=sum;
}
#undef mp
int main(){
int T=gi();
while(T--){
memset(front,0,sizeof(front));cnt=0;
memset(dp,-1,sizeof(dp));
n=gi();m=gi();k=gi();p=gi();
for(int i=1;i<=m;i++){int u=gi(),v=gi(),w=gi();Add(u,v,w);Add(v,u,w);}
dijkstra();int ans=0;flag=0;
for(int i=0;i<=k;i++)
{
Time++;
ans=(ans+dfs(1,i))%p;
}
if(!flag)printf("%d
",ans);
else puts("-1");
}
return 0;
}
奶酪
直接(n^2)枚举两个点然后判断连通性,判断每一个奶酪与上下的连通性,用并查集维护即可.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define re register
#define ll long long
inline int gi(){
int f=1,sum=0;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return f*sum;
}
const int N=1010;
int f[N],n,h,r;
int find(int x){if(f[x]!=x)f[x]=find(f[x]);return f[x];}
struct node{double x,y,z;}c[N];
double dis(int i,int j){
return sqrt((c[i].x-c[j].x)*(c[i].x-c[j].x)+(c[i].y-c[j].y)*(c[i].y-c[j].y)+(c[i].z-c[j].z)*(c[i].z-c[j].z));
}
int main(){
int T=gi();
while(T--){
n=gi();h=gi();r=gi();
for(int i=0;i<=n+1;i++)f[i]=i;
for(int i=1;i<=n;i++)scanf("%lf%lf%lf",&c[i].x,&c[i].y,&c[i].z);
for(int i=1;i<=n;i++)if(c[i].z<=r)f[find(i)]=0;
for(int i=1;i<=n;i++)if(c[i].z>=h-r)f[find(i)]=n+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j && find(i)!=find(j) && dis(i,j)<=2*r)
f[find(i)]=find(j);
if(find(0)==find(n+1))puts("Yes");
else puts("No");
}
return 0;
}
宝藏
(n)的只有12,可以往状压方面想.
不妨设(f_s)表示当前状态为(s)时的最小代价,那么更新就是选一个在(s)里面的点,然后扩展一个不在(s)里面的点,每一次钦定一个开始点即可.记住要用邻接矩阵,不然边数是(2000)而非(n^2).
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define re register
#define ll long long
inline int gi(){
int f=1,sum=0;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return f*sum;
}
const int N=13;
int n,m,front[N],cnt,g[N][N];
int dp[1<<N],dep[N];
void dfs(int s){
for(int u=0;u<n;u++)
if(s&(1<<u))
for(int v=0;v<n;v++)
if(g[u][v]!=g[n][n] && !(s&(1<<v))){
if(dp[s^(1<<v)]>dp[s]+g[u][v]*dep[u]){
int tmp=dep[v];dep[v]=dep[u]+1;
dp[s^(1<<v)]=dp[s]+g[u][v]*dep[u];
dfs(s^(1<<v));
dep[v]=tmp;
}
}
}
int main(){
n=gi();m=gi();memset(g,63,sizeof(g));
for(int i=1;i<=m;i++){
int u=gi(),v=gi(),w=gi();
u--;v--;
g[u][v]=g[v][u]=min(g[u][v],w);
}
int ans=1e9+10;
for(int i=0;i<n;i++){
memset(dp,63,sizeof(dp));
dp[1<<i]=0;dep[i]=1;
dfs(1<<i);
ans=min(ans,dp[(1<<n)-1]);
}
printf("%d
",ans);
return 0;
}
列队
考虑每一次离队变化((x,y))改变的只有第(x)行和最后一列.那么我们对于每一行的前(m-1)个维护一个线段树,最后一列维护一个线段树,然后在对于上面提到的每一个维护一个(vector)存储进队的编号.然后线段树每一次查询然后放到(vector)里面就可以了.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define re register
#define ll long long
inline int gi(){
int f=1,sum=0;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return f*sum;
}
const int N=600010;
int n,m,Max,tot,rt[N];
vector<ll>v[N];
struct node{int ls,rs,sum;}t[N<<4];
void update(int&o,int l,int r,int pos){
if(!o)o=++tot;t[o].sum++;
if(l==r)return;int mid=(l+r)>>1;
if(pos<=mid)update(t[o].ls,l,mid,pos);
else update(t[o].rs,mid+1,r,pos);
}
int query(int o,int l,int r,int v){
if(l==r)return l;
int mid=(l+r)>>1,got=mid-l+1-t[t[o].ls].sum;
if(got>=v)return query(t[o].ls,l,mid,v);
else return query(t[o].rs,mid+1,r,v-got);
}
ll solve2(int,ll);
ll solve1(int,int);
int main(){
n=gi();m=gi();int Q=gi();Max=max(n,m)+Q;
while(Q--){
int x=gi(),y=gi();
if(y==m)printf("%lld
",solve2(x,0));
else printf("%lld
",solve1(x,y));
}
return 0;
}
ll solve2(int x,ll y){
int pos=query(rt[n+1],1,Max,x);update(rt[n+1],1,Max,pos);
ll ans=pos<=n?1ll*pos*m:v[n+1][pos-n-1];
v[n+1].push_back(y?y:ans);
return ans;
}
ll solve1(int x,int y){
int pos=query(rt[x],1,Max,y);update(rt[x],1,Max,pos);
ll ans=pos<m?1ll*(x-1)*m+pos:v[x][pos-m];
v[x].push_back(solve2(x,ans));
return ans;
}