【NOIP2014提高组】【Day1】【解题报告】

这篇博客分享了NOIP2014提高组第一天的比赛解题报告,重点解析了三道题目。第一题是生活大爆炸版石头剪刀布,通过预处理两两之间的关系进行模拟解决。第二题通过数学公式进行枚举计算,复杂度为O(n)。第三题采用动态规划和完全背包优化,将复杂度降低到O(n*m),成功通过所有测试数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

T1:生活大爆炸版石头剪刀布

题目链接:http://codevs.cn/problem/3716/

题解:预处理出两两之间的关系。直接模拟即可。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
int ans1,ans2,t1,t2,c[30][30],n,l1,l2,a[501],b[501];
int main(){
  c[0][2]=1;c[0][3]=1;
  c[1][3]=1;c[2][4]=1;
  c[3][4]=1;c[1][0]=1;
  c[4][0]=1;c[2][1]=1;
  c[4][1]=1;c[3][2]=1;
  c[0][0]=-1;c[1][1]=-1;
  c[2][2]=-1;c[3][3]=-1;
  c[4][4]=-1;
  cin>>n>>l1>>l2;
  for (int i=1;i<=l1;i++) cin>>a[i];
  for (int i=1;i<=l2;i++) cin>>b[i];
  t1=1;t2=1;
  for (int i=1;i<=n;i++){
     if(c[a[t1]][b[t2]]>0)ans1++;
     else if (c[a[t1]][b[t2]]!=-1) ans2++;
	 t1++;t2++;if (t1==l1+1) t1=1;
	 if (t2==l2+1) t2=1; 
  } 
  cout<<ans1<<' '<<ans2<<endl;
}
T2:联合权值

题目链接:http://codevs.cn/problem/3728/

题解:由数学公式可得2ab+2ac+2bc=(a+b+c)^2-a^2-b^2-c^2;

            然后枚举每个点,和这个相连的点两两之间一定能产生联合权值。

            代入那个公式直接算一下就好了。复杂度显然为O(n);

代码:

#include<iostream>
#include<cstdio>
#define N 200010
#define P 10007
using namespace std;
struct use{int st,en;}e[N*2];
long long ans,w[N],maxx;
int cnt,n,a,b,point[N],next[N*2];
void add(int x,int y){
  next[++cnt]=point[x];point[x]=cnt;
  e[cnt].st=x;e[cnt].en=y;	
}
int main(){
   scanf("%d",&n);
   for (int i=1;i<=n-1;i++){scanf("%d%d",&a,&b);add(a,b);add(b,a);}	
   for (int i=1;i<=n;i++) scanf("%lld",&w[i]);
   for (int i=1;i<=n;i++){
     long long tp1(0),tp2(0),mx1(-1),mx2(-1);
     for (int j=point[i];j;j=next[j]){
       (tp1+=w[e[j].en])%=P;(tp2+=w[e[j].en]*w[e[j].en])%=P;	
       if (mx1<w[e[j].en]){mx2=mx1;mx1=w[e[j].en];}
       else mx2=max(mx2,w[e[j].en]);
	 }
     (ans+=(tp1*tp1)%P-tp2+P)%=P;maxx=max(maxx,mx1*mx2);
   }
   cout<<maxx<<' '<<ans<<endl;
}
T3飞扬的小鸟

题目链接:http://codevs.cn/problem/3729/

题解:设f[i][j]为从第0列走到(i,j)的最小步数.

             显然 f[i][j]=max(f[i-1][j+y[i-1]],f[i-1][j-k*x[i-1]]+k);

          这样直接转移显然是O(n*m*k)的。可以得到70分。

          观察一下后半部分.可以发现是完全背包。

          然后用完全背包优化一下就成了O(n*m).足以通过全部的数据。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 10010
#define inf 707406378
using namespace std;
int x[N],y[N],up[N],down[N],f[N][1010],n,m,k,p,ans;
int main(){
  scanf("%d%d%d",&n,&m,&k);up[n]=m+1;down[n]=0;
  for (int i=0;i<n;i++) {scanf("%d%d",&x[i],&y[i]);up[i]=m+1;down[i]=0;}
  for (int i=1;i<=k;i++){scanf("%d",&p);scanf("%d%d",&down[p],&up[p]);}
  memset(f,127/3,sizeof(f));
  for (int i=1;i<=m;i++) f[0][i]=0;
  for (int i=1;i<=n;i++){
     for (int j=x[i-1];j<=m;j++){
      f[i][j]=min(f[i][j],f[i-1][j-x[i-1]]+1);
      f[i][j]=min(f[i][j],f[i][j-x[i-1]]+1); 
      } 
     for (int j=m-x[i-1];j<=m;j++){
       f[i][m]=min(f[i][m],f[i-1][j]+1);
       f[i][m]=min(f[i][m],f[i][j]+1);
     }	   
     for (int j=down[i]+1;j<=up[i]-1;j++){
       if (j+y[i-1]<=m) f[i][j]=min(f[i][j],f[i-1][j+y[i-1]]);
     }
	 for (int j=1;j<=down[i];j++) f[i][j]=inf;
	 for (int j=up[i];j<=m;j++) f[i][j]=inf;   
   }ans=inf;int t=k;
   for (int i=n;i>=1;i--){
     for (int j=down[i]+1;j<up[i];j++) ans=min(ans,f[i][j]);
     if (ans!=inf) break;if (up[i]!=m+1) t--;
   }
   if (t==k){cout<<1<<endl<<ans<<endl;}
   else{cout<<0<<endl<<t<<endl;}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值