zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    8.10
    今日头条笔试题 1~n的每个数,按字典序排完序后,第m个数是什么?
    Gym 100500B Conference Room(最小表示法,哈希)
    CodeForces 438D The Child and Sequence(线段树)
    UVALIVE 6905 Two Yachts(最小费用最大流)
    Gym Conference Room (最小表示法,哈希)
    hdu 2389 Rain on your Parade(二分图HK算法)
    Codeforces Fox And Dinner(最大流)
    zoj 3367 Counterfeit Money(dp)
    ZOJ3370. Radio Waves(2-sat)
  • 原文地址:https://www.cnblogs.com/mleautomaton/p/10962759.html
Copyright © 2011-2022 走看看