NOIP 2014

时间:2022-09-19 11:39:29
    • Prob.1 生活大爆炸版 石头剪刀布

模拟。
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int mp[5][5]={{0,0,1,1,0},
{1,0,0,1,0},
{0,1,0,0,1},
{0,0,1,0,1},
{1,1,0,0,0}};
int A[205],B[205];
int n,lA,lB,ansA,ansB;
int main(){
scanf("%d%d%d",&n,&lA,&lB);
for(int i=1;i<=lA;i++) scanf("%d",&A[i]);
for(int i=1;i<=lB;i++) scanf("%d",&B[i]);
for(int i=1,pA=0,pB=0;i<=n;i++) {
pA++; if(pA>lA) pA=1;
pB++; if(pB>lB) pB=1;
ansA+=mp[A[pA]][B[pB]];
ansB+=mp[B[pB]][A[pA]];
}
printf("%d %d",ansA,ansB);
return 0;
}

    • Prob.2 联合权值

可以叫树形dp吧。
每次考虑把当前子树的根作为长度为2的路径的一个端点或中转点。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 200005
using namespace std;
const int mod=10007;
struct edge{
int to,next;
}e[MAXN*2];
int w[MAXN],head[MAXN];
int sm[MAXN],mx[MAXN];
int n,ent=2,ansx,anss;
void add(int u,int v){
e[ent]=(edge){v,head[u]};
head[u]=ent++;
}
void dfs(int u,int fa){
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
dfs(v,u);
anss=(1ll*anss+1ll*sm[v]*w[u]*2)%mod;
anss=(1ll*anss+1ll*sm[u]*w[v]*2)%mod;
sm[u]+=w[v];
ansx=max(ansx,mx[v]*w[u]);
ansx=max(ansx,mx[u]*w[v]);
mx[u]=max(mx[u],w[v]);
}
}
int main(){
scanf("%d",&n);
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
dfs(1,0);
printf("%d %d",ansx,anss);
return 0;
}

    • Prob.3 飞扬的小鸟

dp+转移优化
首先 70%的很好想:
dp[i][j]表示到达(i,j)的最小点击次数,显然没有后效性。
             ┌dp[i-1][j+y[i-1]] (不点击)
dp[i][j]=min│
             ┕dp[i-1][j-k*x[i-1]]+k(点击)

这个方程的复杂度为 (n*m*m)
考虑优化,发现这样一个东西:
只考虑"点击"这一个转移来源的话,那么
dp[i][j]只比dp[i][j-x[i-1]]多了一个转移来源。
然后就是一个前缀的思想了,即我们把第二维的j从小到大枚举
那么(这里在说"点击"这一个来源)
dp[i][j]=min(dp[i-1][j-x[i-1]],dp[i][j-x[i-1])+1
这样就把"点击"时的O(n)转移优化为了O(1)。

注意j==m时要特殊处理。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define INF 0x3f3f3f3f
using namespace std;
int x[10005],y[10005],l[10005],h[10005],fg[10005];
int dp[10005][1005];
int n,m,k,ans=INF;
bool legal(int i,int j){
if(j<=0||j>m) return 0;
if(!fg[i]) return 1;
return l[i]<j&&j<h[i];
}
void cmin(int &a,int b){
if(a>b) a=b;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
memset(dp,0x3f,sizeof(dp));
for(int i=0;i<n;i++) scanf("%d%d",&x[i],&y[i]);
for(int i=1,p;i<=k;i++) scanf("%d",&p),fg[p]=1,scanf("%d%d",&l[p],&h[p]);
for(int j=l[0]+1;j<(fg[0]?h[0]:m+1);j++) dp[0][j]=0;
for(int i=1;i<=n;i++){
//click
for(int j=0;j<m;j++){
int a=legal(i-1,j-x[i-1])?dp[i-1][j-x[i-1]]:INF;
int b=j>x[i-1]?dp[i][j-x[i-1]]:INF;
cmin(dp[i][j],min(a,b)+1);
}
for(int j=m;j>=0;j--){
int a=legal(i-1,j)?dp[i-1][j]:INF;
cmin(dp[i][m],a+max(m-j-1,0)/x[i-1]+1);
}
//no-click
for(int j=0;j<=m;j++){
int a=legal(i-1,j+y[i-1])?dp[i-1][j+y[i-1]]:INF;
cmin(dp[i][j],a);
}
}
for(int i=n;i>=0;i--){
for(int j=1;j<=m;j++){
if(i==n) cmin(ans,dp[i][j]);
if(i!=n&&legal(i,j)&&dp[i][j]<INF){
printf("%d\n%d",0,k);
return 0;
}
}
if(ans<INF) break;
if(fg[i]) k--;
}
printf("%d\n%d",1,ans);
return 0;
}

    • Prob.4 无线网络发射器选址

二维前缀和,求子矩阵和。
千万不要枚举多了。否则会多统计。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int sum[150][150];
int d,n,ans,cnt;
int area(int x1,int y1,int x2,int y2){
return sum[x2][y2]-sum[x1][y2]-sum[x2][y1]+sum[x1][y1];
}
int main(){
scanf("%d%d",&d,&n);
for(int i=1,x,y,k;i<=n;i++){
scanf("%d%d%d",&x,&y,&k);
x++;y++;
sum[x][y]+=k;
}
for(int i=1;i<=129;i++)
for(int j=1;j<=129;j++)
sum[i][j]=sum[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
for(int i=1,x1,y1,x2,y2,now;i<=129;i++)
for(int j=1;j<=129;j++){
x1=max(i-d-1,0); y1=max(j-d-1,0);
x2=min(i+d,129); y2=min(j+d,129);
now=area(x1,y1,x2,y2);
if(now>ans) ans=now,cnt=0;
if(now==ans) cnt++;
}
printf("%d %d",cnt,ans);
return 0;
}

    • Prob.5 寻找道路

反向BFS给无法到终点的点打上标记,
然后再给那些存在一条出边无法到终点的点打上标记。
最后对没有标记的点跑最短路。(因为边权为1,BFS即可)

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct edge{
int to,next;
}e1[200005],e2[200005];
int head1[10005],head2[10005],vis[10005],dis[10005];
int n,m,ent1=2,ent2=2,S,T;
void add(int u,int v,int &ent,int *head,edge *e){
e[ent]=(edge){v,head[u]};
head[u]=ent++;
}
void BFS1(){
queue<int> q;
vis[T]=1; q.push(T);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head2[u];i;i=e2[i].next){
int v=e2[i].to;
if(vis[v]) continue;
vis[v]=1; q.push(v);
}
}
for(int u=1;u<=n;u++) if(!vis[u])
for(int i=head2[u];i;i=e2[i].next){
int v=e2[i].to;
if(!vis[v]) continue;
vis[v]=-1;
}
}
void BFS2(){
queue<int>q; q.push(S); dis[S]=1;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head1[u];i;i=e1[i].next){
int v=e1[i].to;
if(dis[v]||vis[v]!=1) continue;
dis[v]=dis[u]+1;
q.push(v);
}
}
if(dis[T]==0) printf("-1");
else printf("%d",dis[T]-1);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,u,v;i<=m;i++)
scanf("%d%d",&u,&v),
add(u,v,ent1,head1,e1),
add(v,u,ent2,head2,e2);
scanf("%d%d",&S,&T);
BFS1();
BFS2();
return 0;
}

    • Prob.6 解方程

又是一大神题,车大佬给我讲了好久才明白。
首先按照题目的意思,我们找出x,要使得:
A0 + A1*X1 + A2*X2 + A3*X3 + ...... + An*Xn == 0  [1]
但是无奈 A的范围很大,无法直接计算。
(然后就阴差阳错的考虑到取模上去)
对等式两边同时取模 M(先只对系数取模)
那么得到:(Bi = Ai % M)
B0 + B1*X1 + B2*X2 + B3*X3 + ...... + Bn*Xn == 0  [2]
然后动动脑子,可以发现满足 [1]式的x 则是一定满足 [2]式的x。

!!!
那么我们是不是可以把原来的 [1]式 通过取模后得到系数较小的 [2]式,
然后通过 可以计算的[2]式来找合法的x。

好吧,显然有错。
虽然满足 [1]式的x  一定是满足 [2]式的x,
但是满足 [2]式的x  却不一定是满足[1]式的x。(这个好理解吧)
显然满足 [2]式的x,带入[1]式左边,可能得到两个值,一个是0(合法),一个是k * M(非法)

那怎么办? 接下来就神奇了。
我们多选几个 M(5-6个) : M1 , M2 , M3 ,M4 , M5(M尽量为大素数或某些大素数的乘积
那么对于一个x,在这5种M取模下,如果都满足 [2]式(即其值==0),那么这个x就非常可能是满足 [1]式的,直接把它当做答案。

为什么呢。
如果都满足,那么把这个 x 带入 [1]式后,得到的值要么为 0(合法),要么为 k * M1M2M3M4M5(非法)。
(对于非法的 x,就是带入 [1]式后,其值==k *  M1M2M3M4M5,即是"我们选取的这几个模值的乘积的倍数"。)
而对于所有的x,带入 [1]式后,最多产生 10^6个值。
那么在出题人不知道我们选取的模值的情况下,要使得某个x带入 [1]式后恰好等于"我们选取的模数的乘积的倍数"的几率是很小的。

所以,除非运气不好,否则我们选的几个M (强调:M尽量为大素数或某些大素数的乘积),就可以达到筛选出正确的x的目的。

#include<cctype>
#include<cstdio>
#include<cstring>
#include<iostream>
#define _ %mod[j]
using namespace std;
const int mod[6]={13923, 16851, 24989, 19997, 11987, 13999};
int val[1000005][6]/*mod意义下*/,A[105][6],ANS[1000005];
int n,m,cnt;
void readai(){
int fu;char ch; ch=getchar();
for(int i=0;i<=n;i++){
fu=1;
while(!isdigit(ch)){
if(ch=='-') fu=-1;
ch=getchar();
}
while(isdigit(ch)){
for(int j=0;j<=5;j++)
A[i][j]=(A[i][j]*10+(ch-'0'))_;
ch=getchar();
}
for(int j=0;j<=5;j++) A[i][j]*=fu;
}
}
int Pow(int a,int b,int j){
int now=1;
while(b){
if(b&1) now=(1ll*now*a)_;
a=(1ll*a*a)_;
b>>=1;
}
return now;
}
int cal(int x,int j){
int ans=0;
for(int i=0;i<=n;i++)
ans=(ans+(1ll*A[i][j]*Pow(x,i,j))_)_;
return ans;
}
int main(){
scanf("%d%d",&n,&m);
readai();
for(int j=0;j<=5;j++)
for(int i=1;i<mod[j];i++)
val[i][j]=cal(i,j);
for(int i=1;i<=m;i++){
bool fg=1;
for(int j=0;j<=5;j++)
if(val[(i)_][j]) fg=0;
if(fg) ANS[++cnt]=i;
}
printf("%d\n",cnt);
for(int i=1;i<cnt;i++) printf("%d\n",ANS[i]);
printf("%d",ANS[cnt]);
return 0;
}

NOIP 2014的更多相关文章

  1. NOIP 2014 提高组 题解

    NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...

  2. Luogu 1351 NOIP 2014 联合权值(贪心,计数原理)

    Luogu 1351 NOIP 2014 联合权值(贪心,计数原理) Description 无向连通图 G 有 n 个点,n-1 条边.点从 1 到 n 依次编号,编号为 i 的点的权值为 Wi, ...

  3. 洛谷P1328&equals;&equals;codevs3716 生活大爆炸版石头剪刀布&lbrack;NOIP 2014 day1 T1&rsqb;

    P1328 生活大爆炸版石头剪刀布 1.8K通过 2.6K提交 题目提供者2014白永忻 标签模拟NOIp提高组2014 难度普及- 提交该题 讨论 题解 记录 最新讨论 Who can help m ...

  4. noip 2014 总结

    2014 年的noip 已经结束了,成绩从个人而言不是特别的理想,从今年题的逗的程度,本来是个xxx 就被玩脱了= = 当然现在后悔事没有用的了,不过第二天全屏技术的在最后一小时看到了两道题的错误,然 ...

  5. NOIP 2014 pj &amp&semi; tg

    由于我太弱,去了pj组= = ============================== T1: 傻逼暴力 T2: 傻逼暴力+判断+更新 T3: 手画一下就知道了.算出这个点在第几圈,再使劲yy下在 ...

  6. &lbrack;NOIP 2014复习&rsqb;第三章:动态规划——NOIP历届真题回想

    背包型动态规划 1.Wikioi 1047 邮票面值设计 题目描写叙述 Description 给定一个信封,最多仅仅同意粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定全部的邮票数量都 ...

  7. Noip 2014酱油记&plus;简要题解

    好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...

  8. NOIP 2014 提高组 Day1

    期望得分:100+100+50=250 实际得分:100+100+50=250 此次NOIP  ZJ省一分数线:500,SD:345 https://www.luogu.org/problem/lis ...

  9. &lbrack; NOIP 2014 &rsqb; TG

    \(\\\) \(Day\ 1\) \(\\\) \(\#\ A\) \(Rps\) 定义五种方案的石头剪刀布游戏,两人共进行\(N\)局游戏,已知两人各自的循环节和具体方案,胜者得\(1\)分,败者 ...

  10. 给备战NOIP 2014 的战友们的10条建议

    应老胡要求,要写10条建议= = begin 1. 注意文件关联 比如 halt 前要close(input); close(output); 还有就是一定要打这两句话= = 2. 快排,大家都懂得. ...

随机推荐

  1. javascript(脚本语言)

    javascript(脚本语言)一.注释语法:1.单行注释 //注释内容2.多行注释 /*注释内容*/二.输出语法js语言格式,尽量靠下写,属双标签<script type=”text/java ...

  2. 微软职位内部推荐-Software Engineer II-Web app

    微软近期Open的职位: The Office App Services team is working on the powerful Office Web Apps including Word ...

  3. AngularJS 拦截器和应用例子&lpar;转&rpar;

    $httpAngularJS 的 $http 服务允许我们通过发送 HTTP 请求方式与后台进行通信.在某些情况下,我们希望可以俘获所有的请求,并且在将其发送到服务端之前进行操作.还有一些情况是,我们 ...

  4. JQuery UI进度条——Progressbar

    1.先引入jquery和jquery-ui的js,例子如下: <link href="JqueryUI/jquery-ui.css" rel="stylesheet ...

  5. 解决ie6里png图片透明变白色bug

    加入这段js就行了. function correctPNG() // correctly handle PNG transparency in Win IE 5.5 & 6. { var a ...

  6. 在java中构建json对象,返回给前端页面

    // 给客户端返回一个json对象 StringBuilder sb = new StringBuilder("{"); sb.append("\"name\& ...

  7. Redis支持的数据类型及相应操作命令:String(字符串),Hash(哈希),List(列表),Set(集合)及zset&lpar;sorted set:有序集合&rpar;

    help 命令,3种形式: help 命令 形式 help @<group> 比如:help @generic.help @string.help @hash.help @list.hel ...

  8. C&plus;&plus;旅馆问题。

    有总钱数 有每房每天住需要多少钱 问最少可以住几天 最后输入的是钱数.前边输入没个住所每天多少钱 例如: 1001 1002 1003 1004 1000 -1 100 500 600 最少一天,最多 ...

  9. &lpar;转&rpar;ASP&period;NET MVC 4 RC的JS&sol;CSS打包压缩功能

    转自:http://www.cnblogs.com/shanyou/archive/2012/06/22/2558580.html 打包(Bundling)及压缩(Minification)指的是将多 ...

  10. 存储过程 Mvc 的调用

    /// <summary>        /// 根据条件,使用存储过程分页查询电影        /// </summary>        /// <param na ...