【NOIP2014提高组】【Day1】【解题报告】
2015-10-19 18:51
459 查看
T1:生活大爆炸版石头剪刀布
题目链接:http://codevs.cn/problem/3716/
题解:预处理出两两之间的关系。直接模拟即可。
代码:
题目链接:http://codevs.cn/problem/3728/
题解:由数学公式可得2ab+2ac+2bc=(a+b+c)^2-a^2-b^2-c^2;
然后枚举每个点,和这个相连的点两两之间一定能产生联合权值。
代入那个公式直接算一下就好了。复杂度显然为O(n);
代码:
题目链接: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).足以通过全部的数据。
代码:
题目链接: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 ,maxx; int cnt,n,a,b,point ,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 ,y ,up ,down ,f [1010],n,m,k,p,ans; int main(){ scanf("%d%d%d",&n,&m,&k);up =m+1;down =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;} }
相关文章推荐
- 用户中心登录注册整理
- 如何将虚拟机中的内网IP设置成固定的
- Sqlserver__数据表排序记录和界面显示排序记录不一致的问题
- WPF 键盘全局接收消息
- AndroidWear开发之HelloWorld篇
- 借刀杀对象--Raii技法(C++版)
- 1026. 程序运行时间(15)
- AndroidWear开发之开发环境[前奏]
- my_bolg
- 透视投影模式下近剪裁面剪裁要在剪裁空间进行而不能推迟到归一化设备空间
- I2C从驱动到应用(上篇)
- ExpandableListView的用法(类似QQ好友展示)
- 特征描述之LBP算子
- 解决 Agreeing to the Xcode/iOS license requires admin privileges
- 让div居中
- 日志规范
- Hibernate数据库配置文件中数据库名称错误问题
- 整数、单精度浮点数和双精度浮点数在计算机中的存储格式
- unbuntu下安装伪分布式Hbase
- hdu5266pog loves szh III(RMQ+LCA)