• NOIP2017题解


    小凯的疑惑

    下面没有证明,只有结论

    #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;
    }
    
  • 相关阅读:
    2015.07-2015.08
    the last lecture
    强化的单例属性_Effective Java
    Socket通信客户端设计(Java)
    静态工场方法代替构造器
    如何控制Java中的线程,总结了3种方法...
    如何快速转型,比如C#...to...Java
    C#中var和dynamic
    How to use the Visual Studio
    mark blog
  • 原文地址:https://www.cnblogs.com/mleautomaton/p/10962759.html
Copyright © 2020-2023  润新知