17.10.10

  • 上午
    • 模拟考试(大悲催…)
      • Prob.1(WA

        一个套路,没做过真的好难想出来

        简化题目:

        对于一个整数序列,把任意一个元素修改为任意一个整数为一次操作,问最少需要几次操作可以使得序列(严格)单调上升。

        开始想的是求一个LIS(最长上升子序列),然后发现不对,因为只能修改为整数。

        然后就想不出来了,555

        正解:

        把序列的每个元素的值减去该元素的标号,即a[ i ]-=i ;

        然后再求一个最长不下降子序列,这样求出来的最长序列可以保证:在该最长不下降子序列中的元素不修改的情况下,其他元素一定可以修改成功。

        代码:

        #include<cstdio>
        #include<cstring>
        #include<iostream>
        #include<algorithm>
        using namespace std;
        int lson[100005],rson[100005],key[100005],t[100005],now[100005];
        int n,cnt;
        void DFS(int u){
        	if(lson[u]) DFS(lson[u]);
        	++cnt; t[cnt]=key[u]-cnt;
        	if(rson[u]) DFS(rson[u]);
        }
        void LIS(){
        	cnt=0;
        	for(int i=1;i<=n;i++){
        		if(!cnt||now[cnt]<=t[i]){
        			now[++cnt]=t[i];
        		}
        		else{
        			int l=upper_bound(now+1,now+cnt+1,t[i])-now;
        			now[l]=t[i];
        		}
        	}
        	printf("%d",n-cnt);
        }
        int main(){
        	freopen("binary.in","r",stdin);
        	freopen("binary.out","w",stdout);
        	scanf("%d",&n);
        	for(int i=1;i<=n;i++) scanf("%d",&key[i]);
        	for(int i=2,a,b;i<=n;i++){
        		scanf("%d%d",&a,&b);
        		if(!b) lson[a]=i;
        		else rson[a]=i;
        	}
        	DFS(1);
        	LIS();
        	return 0;
        }
        
  • Prob.2(AC

    一个小技巧:一个序列区间的gcd如果等于该区间的最小值,那么这个区间的所有数都可以被该最小值整除。

    本题两个ST表维护

  • Prob.3(WA

    image

    神题,记忆化搜索

    (S->P)反向考虑交换操作,如果最后一次交换的是a[i]和a[i+1],那么必然在该次交换之前,a[l]~a[i]的值都小于a[i+1]~a[r]。

    所以对于每个成立的a[i],a[i+1],可以把序列分为两段(左一段右一段),然后递归做相同操作。

    然后回溯时对当前递归层的答案贡献

    =左段的方案数*右段的方案数*C(r-l-1,i-l),这个组合数考虑两边的交换顺序

    代码:

    
    
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 using namespace std;
     5 const int mod=1000000007;
     6 int dp[55][55],fac[55],inv[55];
     7 int aa[55],pos[55];
     8 int power(int a,int b)
     9 {
    10     int val=1;
    11     while(b)
    12     {
    13         if(b&1) val=(1ll*val*a)%mod;
    14         a=(1ll*a*a)%mod; b>>=1; 
    15     }
    16     return val;
    17 }
    18 void pre_fac_inv(int n)
    19 {
    20     fac[0]=fac[1]=1;
    21     for(int i=2;i<=n;i++) fac[i]=(1ll*fac[i-1]*i)%mod;
    22     inv[n]=power(fac[n],mod-2);
    23     for(int i=n;i>1;i--) inv[i-1]=(1ll*inv[i]*i)%mod;
    24     inv[0]=inv[1];
    25 }
    26 int C(int m,int n)
    27 {
    28     return 1ll*fac[m]*inv[m-n]%mod*inv[n]%mod;
    29 }
    30 int dfs(int l,int r){
    31     if(l>=r) return 1;
    32     if(dp[l][r]) return dp[l][r];
    33     int maxx[55],minn[55];
    34     memset(maxx,0,sizeof(maxx));
    35     memset(minn,0x3f,sizeof(minn));
    36     int ret=0,numl,numr,ma,mi;
    37     for(int i=l;i<=r;i++){
    38         maxx[i]=aa[i];
    39         if(i!=l) maxx[i]=max(maxx[i],maxx[i-1]);
    40     }
    41     for(int i=r;i>=l;i--){
    42         minn[i]=min(minn[i],aa[i]);
    43         if(i!=r) minn[i]=min(minn[i],minn[i+1]);
    44     }
    45     for(int i=l;i<r;i++){
    46         swap(aa[i],aa[i+1]);
    47         ma=max(maxx[i-1],aa[i]);
    48         mi=min(minn[i+2],aa[i+1]);
    49         if(ma<mi){
    50             numl=dfs(l,i);
    51             numr=dfs(i+1,r);
    52             ret=(1ll*ret+1ll*numl*numr%mod*C(r-l-1,i-l)%mod)%mod;
    53         }
    54         swap(aa[i],aa[i+1]);    
    55     }
    56     return dp[l][r]=ret;
    57 }
    58 int main(){
    59     freopen("swap.in","r",stdin);
    60     freopen("swap.out","w",stdout);
    61     int n;
    62     scanf("%d",&n);
    63     pre_fac_inv(n);
    64     for(int i=1;i<=n;i++) scanf("%d",&aa[i]),aa[i]++;
    65     int ans=dfs(1,n);
    66     printf("%d",ans);
    67     return 0;
    68 }
    View Code
    
    
    
    
    
  • 下午
    • 先改了上午的题
    • 然后绝望的发现入门OJ上的题做不了了!!!
    • 就先把前几天做的12道题的题解贴上。
      • 入门OJ 2036 [Noip模拟题]集合贪心
        将每个数x化为 x=a*(k^b) (a%k!=0) 的形式
        对所有的a排序+离散化
        然后排序x后,从小到大去取,
        取的条件为:当前数的b,与之前取的a与当前数的a相同的且b值最大的那个数的b 差值不为1
        (有点绕,分开描述)
        当前数 x=a1*(k^b)
        之前的那个数 x'=a1*(k^b'),且那个数在这个a1的前提下,b'为最大
        如果 b!=b'+1 则可以取
      代码:
      #include<cstdio>
      #include<cstring>
      #include<iostream>
      #include<algorithm>
      #define ll long long
      using namespace std;
      ll a[100005],c[100005],d[100005],tmp;
      int n,k,m,sub,ans,cnt;
      int main(){
      	scanf("%d%d",&n,&k);
      	for(int i=1;i<=n;i++){
      		scanf("%lld",&a[i]); tmp=a[i];
      		while(tmp%k==0) tmp/=k;
      		c[++m]=tmp;
      	}
      	sort(a+1,a+n+1);
      	sort(c+1,c+m+1); m=unique(c+1,c+m+1)-c-1;
      	for(int i=1;i<=n;i++){
      		tmp=a[i]; cnt=0;
      		while(tmp%k==0) tmp/=k,cnt++;cnt++;
      		sub=lower_bound(c+1,c+m+1,tmp)-c;
      		if(!d[sub]||d[sub]!=cnt-1) ans++,d[sub]=cnt;
      	}	
      	printf("%d",ans);
      	return 0;
      }
      • 入门OJ 2075 [Noip模拟题]调整

        建图:
        首先明确一个观点:
        如果我们把一些边调整为边权为0,
        且计算出起点到终点的最短路值小于等于c
        那么一定可以通过让最短路径上调整过的某些边的边权增加,
        (即一开始就把不把其边权变为0),使得该路径的权值和恰好为c
           
        然后就建一个类似层次图的东西
        第几个层次就表示调整了几条边的权值为0
        对于输入的 u,v,w
        对每个层次 u->v 建边权为w的边
        对每个层次的u->下一个层次的v建一个边权为0的边,经过这条边的话就表示要调整其边权为0
           
        最后从小到大枚举每个层次,若该层次的n号节点的dis<=c,那么该层次就是答案(即调整该层次的序号那么多次)
           
        ...不知为何
        用优先队列优化过的spfa跑得还没有裸的spfa快

        代码:

        #include<queue>
        #include<iostream>
        #include<cstdio>
        #include<cstring>
        using namespace std;
        struct edge{
        	int to,val,next;
        }e[3000000];
        int head[200000],dis[200000];
        bool inq[200000];
        int n,m,c,ent=1;
        void add(int u,int v,int w){
        	e[ent]=(edge){v,w,head[u]};
        	head[u]=ent++;
        }
        void spfa(){
        	memset(dis,0x3f,sizeof(dis));
        	queue<int> q;int u,v;
        	q.push(1);inq[1]=1;dis[1]=0;
        	while(!q.empty()){
        		u=q.front(); q.pop(); inq[u]=0;
        		for(int i=head[u];i;i=e[i].next){
        			v=e[i].to;
        			if(dis[v]<=dis[u]+e[i].val) continue;
        			dis[v]=dis[u]+e[i].val;
        			if(inq[v]) continue;
        			q.push(v);
        			inq[v]=1;
        		}
        	}
        }
        int main(){
        	scanf("%d%d%d",&n,&m,&c);
        	for(int i=1,u,v,w;i<=m;i++){
        		scanf("%d%d%d",&u,&v,&w);
        		for(int j=0;j<=m;j++){
        			add(u+j*n,v+j*n,w);
        			add(u+j*n,v+(j+1)*n,0);
        		}
        	}
        	spfa();
        	for(int i=0;i<=m;i++)
        		if(dis[n+i*n]<=c){
        			printf("%d",i);
        			break;
        		}
        	return 0;
        }
  • 入门OJ 2076 [Noip模拟题]集合

    因为A,B的差值不大于10^6,所以不存在两个数可以靠大于10^6的素数合并
    筛出10^6以内的素数,在筛的同时,用并查集合并。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    ll MAXN=1000000;
    ll prime[1000006],fa[2000006];
    bool np[1000006];
    ll ff,ans,A,B,P,cnt;
    ll find(ll x){
    	return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    void find_and_work(){
    	for(int i=1;i<=B-A+1;i++) fa[i]=i;
    	
    	for(ll i=2;i<=MAXN;i++){
    		if(!np[i]){
    			prime[++cnt]=i;
    			if(i>=P){
    				ff=0;
    				for(ll j=((A-1)/i+1)*i;j<=B;j+=i){
    					int f=find(j-A+1);
    					if(!ff) ff=f;
    					else fa[f]=ff;
    				}
    			}
    		}
    		for(ll j=1;j<=cnt&&prime[j]<=MAXN/i;j++){
    			np[i*prime[j]]=1;
    			if(i%prime[j]==0) break;
    		}
    	}
    }
    
    int main(){
    	scanf("%lld%lld%lld",&A,&B,&P);
    	MAXN=min(MAXN,B);
    	find_and_work();
    	for(ll i=1;i<=B-A+1;i++) if(find(i)==i) ans++;
    	printf("%lld",ans);
    	return 0;
    }
  • 入门OJ 2077 [Noip模拟题]购买

    按c排序后模拟即可

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    struct goods{
    	ll k,c;
    	bool operator <(const goods &rtm) const{
    		return c<rtm.c;
    	}
    }g[105];
    ll n,b=1,m,ans,t;
    int main(){
    	scanf("%lld",&n);
    	for(ll i=1;i<=n;i++) scanf("%lld%lld",&g[i].k,&g[i].c);
    	sort(g+1,g+n+1);
    	scanf("%lld",&t);
    	ll i=1;
    	for(ll j=1,x=0,y=0,z=0;j<=t;j++){
    		scanf("%lld",&x);z=y; y=x; x=x-z;
    		while(x&&i<=n){
    			while(g[i].k<=x&&i<=n){
    				ans+=g[i].k*g[i].c*j;
    				x-=g[i].k;
    				i++;
    			}
    			if(i<=n){
    			ans+=x*g[i].c*j;
    			g[i].k-=x;
    			x=0;
    			}
    		}
    	}
    	while(i<=n){
    		ans+=g[i].k*g[i].c*(t+1);
    		i++;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
  • 入门OJ 2078 [Noip模拟题]填充棋盘

    看题解吧(看不到了诶)
    神奇组合题。

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int mod=1000000007;
    int n,m,ans;
    int pow(int a,int b){
    	int val=1;
    	while(b){
    		if(b&1) val=1ll*val*a%mod;
    		a=1ll*a*a%mod;
    		b>>=1;
    	}
    	return val;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	ans=(1ll*6*(1ll*pow(2,n)+1ll*pow(2,m))-24)%mod;
    	printf("%d",ans);
    	return 0;
    }
    
  • 入门OJ 2081 [Noip模拟题]画山

    dp(背包+递推) 好题

    定义dp[i][j]表示终点在(i,j)的方法数,
    然后每次枚举线段,从前面转移过来:
    dp[i][j]+=dp[i-a],[j-b]
    显然有重复呢。
     
    为了去重,把斜率加入dp状态,
    dp[i][j][k]:表示终点在(i,j)时,且到达改点用的是斜率编号为k的线段。
    目的是每次转移时不能从相同的k转移
    此时,就不能类同上面一样枚举每个线段来转移,(否则会少记录方案)
    而是应该先预处理,把相同斜率的线段归为一组,然后对每一组跑一个物品无限的背包,
    计算出该斜率下可以延伸多长
    然后dp时,枚举每一组斜率,然后枚举背包跑出的可以到达的距离,然后转移。

    O(N*N*M*P)

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const ll mod=1000000007;
    struct segment{
    	int a,b;
    	bool operator <(const segment &rtm) const{
    		return b*rtm.a<rtm.b*a;
    	}
    }seg[105];
    struct group{
    	int a,b;
    	bool can[105];
    }gro[105];
    ll dp[105][105][105],s[105][105];
    int gnt,n,m,p;
    int main(){
    	scanf("%d%d%d",&n,&m,&p);
    	for(int i=1;i<=p;i++) scanf("%d%d",&seg[i].a,&seg[i].b);
    	sort(seg+1,seg+p+1);
    	int st=1; bool *f;
    	for(int I=1;I<=p+1;I++){
    		if(I==p+1||(seg[I].b*seg[st].a!=seg[I].a*seg[st].b)){
    			++gnt;
    			gro[gnt].a=seg[st].a; 
    			gro[gnt].b=seg[st].b;
    			f=gro[gnt].can; f[0]=1;
    			for(int i=st;i<I;i++)
    				for(int j=seg[i].a;j<=n;j++)
    					f[j]=f[j]|f[j-seg[i].a];
    			st=I;
    		}
    	}
    	s[0][0]=1;
    	for(int i=0;i<=n;i++)
    		for(int j=0;j<=m;j++)
    			for(int k=1;k<=gnt;k++){
    				for(int o=1;o<=n;o++) if(gro[k].can[o]){
    					int ii=o,jj=ii*gro[k].b/gro[k].a;
    					if(i-ii<0||j-jj<0||j-jj>m) break;
    					dp[i][j][k]=(dp[i][j][k]+s[i-ii][j-jj]-dp[i-ii][j-jj][k]+mod)%mod;
    				}
    				s[i][j]=(s[i][j]+dp[i][j][k]+mod)%mod;
    			}
    	printf("%lld",s[n][0]);
    	return 0;
    }
    
  • 入门OJ 2082 [Noip模拟题]益智游戏

    益智好题
       
    可以明确的是两个人如果会走到相同的一些点,那么这些点一定是连续的
    (都是走最短路嘛)
       
    对于每个人,求出他的最短路DAG图(最短路不止一条啦)
       
    怎么求这个对短路DAG图呢?
    对起点和终点分别跑一次最短路,得到两个dis数组(dis1是从起点跑得,dis2是从终点跑的)
    对于一条边的 u v w,若dis1[u]+dis2[v]+w==dis(起点->终点),那么这条边就在最短路DAG中
       
    然后呢,取出两个人的最短路DAG图中都走的边构成一个新图
    对新图按按拓扑序进行最长路dp。
       
    特判两个人的最短路DAG图是否有相交,
    相交的话,答案要加一,因为dp值是最长路,而要求的是点数
    不相交的话,就不用加了,因为ans本来就等于0;

    代码:

    #include<queue> 
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define INF 0x3f3f3f3f3f3f3f3f
    #define ll long long
    #define node(a,b) (node){a,b}
    using namespace std;
    struct node{
    	ll id,d;
    	bool operator <(const node &rtm) const{
    		return d>rtm.d;
    	}
    };
    struct edge{
    	ll from,to,val,next; 
    }e1[200005],e2[200005],e3[200005];
    ll head1[50005],head2[50005],head3[50005];
    ll dis1[50005],dis2[50005],dis3[50005],in[50005];
    bool fg[50005],ve[200005],xj;
    ll n,m,A,B,C,D,ent1=1,ent2=1,ent3=1,disab,discd,ans;
    void add(ll u,ll v,ll w,ll *head,edge *e,ll &ent){
    	e[ent]=(edge){u,v,w,head[u]}; head[u]=ent++;
    }
    ll dijistra(ll st,ll ed,ll *head,ll *dis,edge *e){
    	static bool vis[50005]; 
    	memset(vis,0,sizeof(bool)*(n+3));
    	memset(dis,0x3f,sizeof(ll)*(n+3));
    	priority_queue<node>q; node now; 
    	ll u,v; dis[st]=0;
    	q.push(node(st,0)); 
    	while(!q.empty()){
    		now=q.top(); q.pop(); u=now.id;
    		if(vis[u]) continue; vis[u]=1;
    		for(ll i=head[u];i;i=e[i].next){
    			v=e[i].to;
    			if(vis[v]||dis[v]<=dis[u]+e[i].val) continue;
    			dis[v]=dis[u]+e[i].val;
    			q.push(node(v,dis[v]));
    		}
    	}
    	return dis[ed];
    }
    void topo(ll st,ll ed,ll *head,ll *dis,edge *e){
    	queue<int>q;
    	for(int i=1;i<=n;i++) if(!in[i]) q.push(i);
    	while(!q.empty()){
    		int u=q.front(); q.pop();
    		ans=max(ans,dis[u]);
    		for(int i=head[u];i;i=e[i].next){
    			int v=e[i].to;
    			dis[v]=max(dis[v],dis[u]+1);
    			in[v]--;
    			if(!in[v])q.push(v);
    		}
    	}
    }
    int main(){
    	//freopen("in.in","r",stdin);
    	scanf("%lld%lld",&n,&m);
    	for(ll i=1,a,b,c;i<=m;i++){
    		scanf("%lld%lld%lld",&a,&b,&c);
    		add(a,b,c,head1,e1,ent1);
    		add(b,a,c,head2,e2,ent2);
    	}
    	scanf("%lld%lld%lld%lld",&A,&B,&C,&D);
    	disab=dijistra(A,B,head1,dis1,e1);
    	disab=dijistra(B,A,head2,dis2,e2);
    	if(disab==INF){printf("-1");return 0;}
    	for(int i=1;i<ent1;i++){
    		int u=e1[i].from,v=e1[i].to,w=e1[i].val;
    		if(dis1[u]+dis2[v]+w==disab) fg[u]=fg[v]=1,ve[i]=1;
    	}
    	discd=dijistra(C,D,head1,dis1,e1);
    	discd=dijistra(D,C,head2,dis2,e2);
    	if(discd==INF){printf("-1");return 0;}
    	for(int i=1;i<ent1;i++){
    		int u=e1[i].from,v=e1[i].to,w=e1[i].val;
    		if(dis1[u]+dis2[v]+w==discd){
    			if(fg[u]||fg[v]) xj=1;
    			if(!ve[i]) continue;
    			add(u,v,w,head3,e3,ent3);
    			in[v]++;			
    		}
    	}
    	topo(C,D,head3,dis3,e3);
    	if(xj) ans++;
    	printf("%lld",ans);
    	return 0;
    }
  • 入门OJ 2083 [Noip模拟题]围篱笆

    和上题一样,也是一道"益智"题

    代码:

    #include<cmath> 
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const double pi=acos(-1);
    int N;
    int main(){
    	while(1){
    		scanf("%d",&N);
    		if(!N) break;
    		printf("%.2lf
    ",1.0*N*N/pi/2);
    	}
    	return 0;
    }
  • 入门OJ 2084 [Noip模拟题]点

    假题,其实选的点可以和原来的点重合。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<windows.h> 
    #define happy_check(); 
    int RESULT=MessageBox(NULL,TEXT("Are you happy?"),"Just click on it" ,MB_YESNO);if(RESULT==IDNO){
    MessageBox(NULL,TEXT("Poor guy!
    Hope you can be better."),"You are not happy?" ,MB_OK);return 0;}
    using namespace std;
    int x[10005],y[10005];
    int n,lx,ly,cnt,xx,yy,ans;
    int abs(int a){
    	return a<0?-a:a;
    }
    int main(){
    	//happy_check();
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]);
    	sort(x+1,x+n+1); sort(y+1,y+n+1);
    	if(n&1) cnt=1,xx=x[n/2+1],yy=y[n/2+1]; 
    	else{
    		xx=x[n/2]; lx=x[n/2+1]-x[n/2]+1;
    		yy=y[n/2]; ly=y[n/2+1]-y[n/2]+1;
    		cnt=lx*ly;
    	}
    	for(int i=1;i<=n;i++) ans+=abs(xx-x[i]);
    	for(int i=1;i<=n;i++) ans+=abs(yy-y[i]);
    	printf("%d %d",ans,cnt);
    	return 0;
    }
    
  • 入门OJ 2085 [Noip模拟题]身高

    对于每个约束(a,b)
    那么a,b之间的应该都比a和b小,所以就差分使得该区间整体小一
    注意有重复的(a,b),要去重,否则WA

    (怎么有一个输入的东西没用上?)

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    struct cons{
    	int a,b;
    	bool operator <(const cons &rtm) const{
    		return a!=rtm.a?a<rtm.a:b<rtm.b;
    	}
    }t[100005];
    int dif[100005];
    int N,I,H,R;
    int main(){
    	scanf("%d%d%d%d",&N,&I,&H,&R);
    	for(int i=1;i<=R;i++){
    		scanf("%d%d",&t[i].a,&t[i].b);
    		if(t[i].a>t[i].b) swap(t[i].a,t[i].b);
    	}
    	sort(t+1,t+R+1);
    	for(int i=1,j=0;i<=R;i++){
    		if(t[i].a==t[j].a&&t[i].b==t[j].b) continue;
    		dif[t[i].a+1]-=1;
    		dif[t[i].b]+=1;
    		j=i;
    	}
    	for(int i=1;i<=N;i++){
    		H+=dif[i];
    		printf("%d
    ",H);
    	}
    	return 0;
    }
    
  • 入门OJ 2087 [Noip模拟题]lucky

    裸的数位Dp
    输入的数不超过10^20,可能爆long long(包括unsigned long long)
    所以用字符串读入
    (一直wa,最后才发现读入出错了)

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define ll long long
    using namespace std;
    ll dp[30][12][2];
    ll N,tail,num[30]; 
    ll dfs(int p,int last,bool ach,bool up){
    	if(p>tail) return ach;
    	if(!up&&dp[p][last][ach]!=-1) return dp[p][last][ach];
    	ll ret=0; int r=up?num[p]:9;
    	for(int i=0;i<=r;i++) 
    		ret+=dfs(p+1,i,ach||(last==4&&i==9),up&&i==r);
    	if(!up) return dp[p][last][ach]=ret;
    	return ret;
    }
    int main(){
    	num[++tail]=getchar()-'0';
    	while(num[tail]<0||num[tail]>9) num[tail]=getchar()-'0';
    	while(num[tail]<=9&&num[tail]>=0) num[++tail]=getchar()-'0';
    	tail--;
    	memset(dp,-1,sizeof(dp));
    	cout<<dfs(1,0,0,1);
    	return 0;
    }
    
  • 入门OJ 2088 [Noip模拟题]小球

    模拟,做了超过100000次就停下来

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    int A,B,cnt; 
    int main(){
    	scanf("%d%d",&A,&B);
    	while(1){
    		if(A>B) swap(A,B);
    		if(!A) break;
    		B-=A;	A+=A;
    		cnt++;
    		if(cnt>100000){
    			printf("-1");
    			return 0;
    		}
    	}
    	printf("%d",cnt);
    	return 0;
    }
  • 晚上
    • BZOJ 1011 [HNOI2008]遥远的行星

      扯题。
          利用题目给的答案误差(大佬博客 ↓)
         
      http://www.cnblogs.com/Sunnie69/p/5575626.html

      代码:

      #include<cstdio>
      #include<cstring>
      #include<iostream>
      #define MAXN 100005 
      using namespace std;
      const double eps=1e-8;
      double m[MAXN],s[MAXN];
      double A,ans;int n,p,B;
      int main(){
          scanf("%d%lf",&n,&A);
          for(int i=1;i<=n;i++) scanf("%lf",&m[i]),s[i]=s[i-1]+m[i];
          p=min(2000,n);
          for(int i=1;i<=p;i++){
              ans=0;
              B=(int)(A*i+eps);
              for(int j=1;j<=B;j++) ans+=m[j]/(1.0*i-j);
              printf("%.6lf
      ",ans*m[i]);
          }
          for(int i=p+1;i<=n;i++){
              B=(int)(A*i+eps);
              ans=m[i]*s[B]/(1.0*i-1.0*B/2);
              printf("%.6lf
      ",ans);
          }
          return 0;
      }
    • BZOJ 1013 [JSOI2008]球形空间产生器sphere

      设出中心的多维坐标
      由给出的n+1个点得出n个等式,
      用高斯消元计算出线性方程的各个元的值
         
      至于高斯消元,自己模拟就好了。

      代码:

      #include<cstdio>
      #include<cstring>
      #include<iostream>
      using namespace std;
      double k[15][15],w[2][15],d[15];
      int n;
      void Gaussian(int p){
      	if(p>n) return;
      	double b,val=0;
      	for(int r=p+1;r<=n;r++){
      		b=k[r][p]/k[p][p];
      		for(int i=p;i<=n+1;i++)
      			k[r][i]=k[r][i]-k[p][i]*b;
      	}
      	Gaussian(p+1);
      	for(int i=p+1;i<=n;i++)
      		val+=d[i]*k[p][i];
      	d[p]=(k[p][n+1]-val)/k[p][p];
      }
      int main(){
      	int cur=0;
      	scanf("%d",&n);
      	for(int i=1;i<=n;i++)scanf("%lf",&w[cur][i]);
      	for(int r=1;r<=n;r++){
      		cur^=1;
      		for(int i=1;i<=n;i++)scanf("%lf",&w[cur][i]);
      		for(int i=1;i<=n;i++){
      			k[r][i]=2*(w[cur^1][i]-w[cur][i]);
      			k[r][n+1]=k[r][n+1]+w[cur^1][i]*w[cur^1][i]-w[cur][i]*w[cur][i];
      		}
      	}
      	Gaussian(1);
      	for(int i=1;i<n;i++)
      		printf("%.3lf ",d[i]);
      	printf("%.3lf",d[n]);
      	return 0;
      }
      
    • BZOJ 1012 [JSOI2008]最大数maxnumber

      可以线段树。
       
      注意到如果向队尾加入一个元素,
      且它前面的元素比它小的话,那么无论怎么询问,它前面的元素都不可能贡献答案
      所以维护一个单调栈,有了单调性后,二分寻找答案。

      代码:

      #include<cstdio>
      #include<cstring>
      #include<iostream>
      #include<algorithm> 
      using namespace std;
      int num[200005],pos[200005];
      int N,D,t,cnt,top,l;
      int main(){
      	scanf("%d%d",&N,&D);
      	char com; int x;
      	for(int i=1;i<=N;i++){
      		scanf(" %c%d",&com,&x);
      		if(com=='A'){
      			++cnt; x=(x+t)%D;
      			while(top&&num[top]<=x) top--;
      			num[++top]=x;
      			pos[top]=cnt;
      		}
      		else if(com=='Q'){
      			x=cnt-x+1;
      			l=lower_bound(pos+1,pos+top+1,x)-pos;
      			t=num[l];
      			printf("%d
      ",t);
      		}
      	}
      	return 0;
      }
      
原文地址:https://www.cnblogs.com/zj75211/p/7646581.html