[ NOIP 2014 ] TG
\(\\\)
\(Day\ 1\)
\(\\\)
\(\#\ A\) \(Rps\)
定义五种方案的石头剪刀布游戏,两人共进行\(N\)局游戏,已知两人各自的循环节和具体方案,胜者得\(1\)分,败者或平局均不得分,求\(N\)局后两人得分。
- \(N\in [0,200]\)
- 将二维的计分表填满,模拟。
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 210
#define n1 x[0]
#define n2 y[0]
#define R register
#define gc getchar
using namespace std;
int n,x[N],y[N];
int res[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}
};
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
int main(){
n=rd(); n1=rd(); n2=rd();
for(R int i=1;i<=n1;++i) x[i]=rd();
for(R int i=1;i<=n2;++i) y[i]=rd();
int px=0,py=0,ansx=0,ansy=0;
for(R int i=1;i<=n;++i){
px=(px==n1)?1:px+1;
py=(py==n2)?1:py+1;
ansx+=res[x[px]][y[py]];
ansy+=res[y[py]][x[px]];
}
printf("%d %d",ansx,ansy);
return 0;
}
\(\\\)
\(\# B\) \(Link\)
给出一棵\(N\)个节点的树,每个边的边权都为\(1\),每个点都有权值\(W_i\),对于图\(G\)上的任意点对\((u,v)\),若它们的最短距离为\(2\),则它们之间会产生\(W_v \times W_u\)的联合权值,求:
- 整棵树所有点对中能够产生的最大联合权值
- 整棵树的所有能产生联合权值的点对间联合权值之和\((\)对\(10007\)取模\()\)
- \(N\in [0,2\times 10^5]\),\(W_i\in [0,10^4]\)
- 每个能产生联合权值的点对必然会跨过一个中间点,也就是说,一个能产生联合权值的点对,必然存在一个另外的点,与这个点对中的两个点有边相连。
- 考虑枚举这个中间点,那么他直接连边的所有点任选两个都会产生联合权值,考虑用一种类似前缀和的方法,顺序扫描所有出边,每个点只与在它前面被扫描到的点\((\)仅本次枚举中间点所扫描到的点\()\)产生联合权值,这样计数可以保证复杂度对于每个点是线性的,并且不会重复计数。
- 对于最大值部分只需要在扫描过程中记录当前点所引出的点中最大权值点和次大权值点,每扫描一条出边就尝试更新最大值和次大值,最后得到的两个数相乘就是以当前点为中间点所能产生的最大联合权值。
- 注意点对是有序的,所以求和部分最后要取双倍答案。
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 200010
#define R register
#define gc getchar
#define mod 10007
using namespace std;
int n,tot,ansmx,ans,hd[N],val[N];
struct edge{int to,nxt;}e[N<<1];
inline void add(int u,int v){
e[++tot].to=v; e[tot].nxt=hd[u]; hd[u]=tot;
}
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
inline void calc(int u){
int sum=0,mx=0,sx=0;
for(R int i=hd[u],v;i;i=e[i].nxt){
v=e[i].to;
if(val[v]>mx){sx=mx;mx=val[v];}
else if(val[v]>sx) sx=val[v];
(ans+=sum*val[v])%=mod;
(sum+=val[v])%=mod;
}
ansmx=max(ansmx,mx*sx);
}
int main(){
n=rd();
for(R int i=1,u,v;i<n;++i){
u=rd(); v=rd(); add(u,v); add(v,u);
}
for(R int i=1;i<=n;++i) val[i]=rd();
for(R int i=1;i<=n;++i) calc(i);
printf("%d %d",ansmx,(ans<<1)%mod);
return 0;
}
\(\\\)
\(\#C\) \(Bird\)
\(Flappy\ Bird\),问题简化到了二维平面上,规定每次向上一次上升高度和每个位置不上升时的下降高度,具体问题描述见题目链接。
- \(N\in [1,10^4]\),\(M\in [1,10^3]\)
设\(f[i][j]\)表示处理到第\(i\)列,到达高度为\(j\)的最少点击次数。
有显然的初始化\(f[i][j]=\infty\ \bigg|\ i\in[1,N],j\in[0,M]\),注意到起点不能是地面,所以还有\(f[0][0]=\infty\)。
先不考虑水管高度和下降操作,对于每一个坐标\((i,j)\),有显然的\(\text O(NM^2)\)的转移\(\begin{align} f[i][j]=min\{f[i-1][j-k\times up_i]+k\ \big| \ 1≤k≤\frac{j}{up_i}\}\end{align}\)
注意到转移方程都是统一的形式,\(f[i][j-up_i]\)已经帮助完成了除去\(f[i-1][j-up_i]\)以外的其他部分答案的统计,所以转移可以优化成\(\text O(NM)\)的形式:\(\begin{align}f[i][j]=min(f[i-1][j-up_i],f[i][j-up_i])+1\end{align}\)
注意到顶部的限制,\(f[i][M]\)的转移就多了很多,但是同样可以采用类似的方法优化:\(\begin{align}f[i][M]=min\{f[i][k]+1\ \big|\ k\in [M-up_i,M]\}\end{align}\)
然后再考虑下降部分,之所以这样按排顺序,是因为如果先更新下降部分的策略,可能会导致同一位置下降和上升同时出现,不合法。此部分的转移显然:\(\begin{align} f[i][j]=min(f[i][j],f[i-1][j+dn_i]\ \big|\ j+dn_i\le M) \end{align}\)
最后要考虑继续向后更新的合法性,将水管部分的答案全部重置为\(\infty\)。
答案可以倒着寻找,找到一个位置\(DP\)值不为\(\infty\)的即可作为答案,注意同时要更新经过的水管数。
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 10010
#define M 1010
#define R register
#define gc getchar
#define inf 2000000000
using namespace std;
int n,m,x,u[N],d[N],mx[N],mn[N],f[N][M];
inline int rd(){
int x=0; char c=gc();
while(!isdigit(c)) c=gc();
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x;
}
int main(){
n=rd(); m=rd(); x=rd();
for(R int i=1;i<=n;++i){
u[i]=rd(); d[i]=rd(); mx[i]=m; mn[i]=1;
}
for(R int i=1,p;i<=x;++i){
p=rd(); mn[p]=rd()+1; mx[p]=rd()-1;
}
for(R int i=1;i<=n;++i)
for(R int j=0;j<=m;++j) f[i][j]=inf;
for(R int i=1;i<=n;++i){
for(R int j=1;j<=m;++j){
if(j>=u[i]) f[i][j]=min(f[i][j],min(f[i-1][j-u[i]],f[i][j-u[i]])+1);
if(j==m) for(R int k=j-u[i];k<=m;++k)
f[i][j]=min(f[i][j],min(f[i-1][k],f[i][k])+1);
}
for(R int j=mn[i];j<=mx[i];++j)
if(j+d[i]<=m) f[i][j]=min(f[i][j],f[i-1][j+d[i]]);
for(R int j=0;j<mn[i];++j) f[i][j]=inf;
for(R int j=mx[i]+1;j<=m;++j) f[i][j]=inf;
}
int ans=inf,cnt=x;
for(R int i=n;i;--i){
for(R int j=mn[i];j<=mx[i];++j) ans=min(ans,f[i][j]);
if(ans<inf) break;
if(mx[i]<m) --cnt;
}
(cnt==x)?printf("1\n%d\n",ans):printf("0\n%d\n",cnt);
return 0;
}
\(\\\)
\(Day\ 2\)
\(\\\)
\(\#\ A\) \(Wireless\)
一个\(130\times 130\)的表格,一些格点有权,现在挑一个格点为中心选一个边长为\(2d\)的正方形,求这个正方形内\((\)含边界\()\)权值和最大值,以及可以产生此最大值的格点个数。
- \(d\in [1,20]\),\(V_{ij}\in [0,10^6]\)
- 显然我们可以讲整个表格求二维前缀和,这样即可\(\Theta(1)\)地求出一个子正方形的权值。
- 把所有格点扫一遍即可,需要注意的是不能直接枚举子正方形顶点,因为会漏掉以边界为中心的一些子正方形,直接按照题目所说枚举中心点即可避免。
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 150
#define R register
#define gc getchar
using namespace std;
int n,d,res,cnt=1,sum[N][N];
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
int main(){
d=rd(); n=rd();
memset(sum,0,sizeof(sum));
for(R int i=1,x,y;i<=n;++i){
x=rd()+1; y=rd()+1; sum[x][y]+=rd();
}
for(R int i=1;i<N;++i)
for(R int j=1;j<N;++j)
sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
for(R int i=1;i<=129;++i)
for(R int j=1;j<=129;++j){
int x=i+d,y=j+d;
int ans=sum[x][y]-sum[max(0,x-2*d-1)][y]-sum[x][max(0,y-2*d-1)]+sum[max(0,x-2*d-1)][max(0,y-2*d-1)];
if(ans==res) ++cnt;
if(ans>res) res=ans,cnt=1;
}
printf("%d %d\n",cnt,res);
return 0;
}
\(\\\)
\(\#B\) \(Road\)
给出一张\(N\)个点\(M\)条边的有向图,且所有边权均为\(1\),现规定起点\(U\)和终点\(V\),找出一条从\(U\)到\(V\)的最短路径,且该路径需满足:路径上的所有点的出边所指向的点都直接或间接与终点连通。
求出符合条件的路径的长度,若不存在一条合法路径则输出"\(-1\)"。
- \(N\in [2,10^4]\),\(M\in [1,2\times 10^5]\)
把问题转化为最短路,需要去掉所有满足“出边所指向的点中存在不与终点连通的点”的所有点,以及所有不与终点连通的点。
考虑正向求是否可达并不好处理,正难则反,把图建为原图的反图,从\(N\)开始做一遍\(BFS\)即可确定原图中每个点是否与终点连通,这样我们即可去除所有不与终点连通的点。
第一类不合法是由于联通了第二类不合法点导致的,所以在反图中我们同样可以找到原图里联通第二类不合法点的点,把他们也打上不合法标记,注意,这里的标记不能直接在原来存储第二类不合法点的数组中记录。
把不合法点都去除后,从\(N\)做一遍最短路即可。
#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 10010
#define M 200010
#define R register
#define gc getchar
#define inf 10000000
using namespace std;
bool vis[N],valid[N];
int n,m,tot,hd[N],dis[N],U,V;
struct edge{int to,nxt;}e[M];
inline void add(int u,int v){
e[++tot].to=v; e[tot].nxt=hd[u]; hd[u]=tot;
}
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
queue<int> q;
inline void bfs(){
q.push(V); vis[V]=1;
while(!q.empty()){
int u=q.front(); q.pop();
for(R int i=hd[u],v;i;i=e[i].nxt)
if(!vis[v=e[i].to]){
q.push(v); vis[v]=1;
}
}
for(R int i=1;i<=n;++i) valid[i]=vis[i];
for(R int i=1;i<=n;++i)
if(!vis[i]) for(R int j=hd[i];j;j=e[j].nxt) valid[e[j].to]=0;
}
priority_queue<pair<int ,int> >h;
inline void dij(){
for(R int i=0;i<=n;++i) dis[i]=inf,vis[i]=0;
dis[V]=0; h.push(make_pair(0,V));
while(!h.empty()){
int u=h.top().second; h.pop();
if(vis[u]) continue; vis[u]=1;
for(R int i=hd[u],v;i;i=e[i].nxt)
if(valid[v=e[i].to]&&dis[v]>dis[u]+1){
dis[v]=dis[u]+1; h.push(make_pair(-dis[v],v));
}
}
}
int main(){
n=rd(); m=rd();
for(R int i=1,u,v;i<=m;++i){u=rd(); v=rd(); add(v,u);}
U=rd(); V=rd(); bfs(); dij();
printf("%d\n",dis[U]==inf?-1:dis[U]);
return 0;
}
\(\\\)
\(\#C\) \(Equation\)
已知多项式方程:
\(\begin{align}a_0+a_1x+a_2x^2+\cdots+a_Nx^N=0\end{align}\)
求这个方程在\([1,M]\)内的整数解(\(N\)和\(M\)均为正整数)。
- \(N\in [1,100]\),\(|a_i|\le 10^{10000}\),\(M\in [0,10^6]\)
秦九韶公式减少方程计算次数,将\(x\)的每一层都嵌套起来,将方程变为如下形式:\(\begin{align}a_0+x(a_1+x(a_2+x(a_3+x(...+xa_n)...)))=0\end{align}\)此时,我们只需计算\(N\)次加法和\(N\)次乘法即可得到等式左边的答案。
枚举\([1,M]\)内的所有数,暴力带入验证即可,注意到系数给的非常大,即使是高精乘法也会超时,我们可以采用哈西的思想,将系数和计算所得都对同一个质数取模,验证最后的答案。这样的做法是不严谨的,所以我们考虑多用几个冲突较少的大质数去完成计算。
下面附的代码在洛谷上可通过,应该是当年\(Noip\)的数据,\(BZOJ\)上的数据加强了,这个版本的代码会超时到死都没有卡过40组数据10s的时限。
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 110
#define M 1000010
#define R register
#define gc getchar
#define mod1 998244353ll
#define mod2 2147483647ll
#define mod3 3221225473ll
using namespace std;
typedef long long ll;
ll n,m,res[M],a[3][N];
inline void rd(ll p){
bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){
a[0][p]=((a[0][p]<<1)+(a[0][p]<<3)+(c^48))%mod1;
a[1][p]=((a[1][p]<<1)+(a[1][p]<<3)+(c^48))%mod2;
a[2][p]=((a[2][p]<<1)+(a[2][p]<<3)+(c^48))%mod3;
c=gc();
}
if(f){
a[0][p]=-a[0][p]; a[1][p]=-a[1][p]; a[2][p]=-a[2][p];
}
}
inline bool valid(ll x){
ll ans[3]={0ll,0ll,0ll};
for(R int i=n;i;--i){
ans[0]=(ans[0]+a[0][i])*x%mod1;
ans[1]=(ans[1]+a[1][i])*x%mod2;
ans[2]=(ans[2]+a[2][i])*x%mod3;
}
(ans[0]+=a[0][0])%=mod1;
(ans[1]+=a[1][0])%=mod2;
(ans[2]+=a[2][0])%=mod3;
return (ans[0]==0&&ans[1]==0&&ans[2]==0);
}
int main(){
scanf("%lld%lld",&n,&m);
for(R ll i=0;i<=n;++i) rd(i);
for(R ll i=1;i<=m;++i) if(valid(i)) res[++res[0]]=i;
printf("%lld\n",res[0]);
for(R ll i=1;i<=res[0];++i) printf("%lld\n",res[i]);
return 0;
}
[ NOIP 2014 ] TG的更多相关文章
- NOIP 2014 提高组 题解
NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...
- Luogu 1351 NOIP 2014 联合权值(贪心,计数原理)
Luogu 1351 NOIP 2014 联合权值(贪心,计数原理) Description 无向连通图 G 有 n 个点,n-1 条边.点从 1 到 n 依次编号,编号为 i 的点的权值为 Wi, ...
- noip 2014 提高组初赛
noip 2014 提高组初赛 一. TCP协议属于哪一层协议( ) A. 应用层 B. 传输层 C. 网络层 D. 数据链路层 B TCP(传输控制协议) 若有变量int a; float: x, ...
- NOIP 2014 pj & tg
由于我太弱,去了pj组= = ============================== T1: 傻逼暴力 T2: 傻逼暴力+判断+更新 T3: 手画一下就知道了.算出这个点在第几圈,再使劲yy下在 ...
- 洛谷P1328==codevs3716 生活大爆炸版石头剪刀布[NOIP 2014 day1 T1]
P1328 生活大爆炸版石头剪刀布 1.8K通过 2.6K提交 题目提供者2014白永忻 标签模拟NOIp提高组2014 难度普及- 提交该题 讨论 题解 记录 最新讨论 Who can help m ...
- noip 2014 总结
2014 年的noip 已经结束了,成绩从个人而言不是特别的理想,从今年题的逗的程度,本来是个xxx 就被玩脱了= = 当然现在后悔事没有用的了,不过第二天全屏技术的在最后一小时看到了两道题的错误,然 ...
- [NOIP 2014复习]第三章:动态规划——NOIP历届真题回想
背包型动态规划 1.Wikioi 1047 邮票面值设计 题目描写叙述 Description 给定一个信封,最多仅仅同意粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定全部的邮票数量都 ...
- Noip 2014酱油记+简要题解
好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...
- NOIP 2014 提高组 Day1
期望得分:100+100+50=250 实际得分:100+100+50=250 此次NOIP ZJ省一分数线:500,SD:345 https://www.luogu.org/problem/lis ...
随机推荐
- nyoj 95 众数问题(set)
众数问题 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 所谓众数,就是对于给定的含有N个元素的多重集合,每个元素在S中出现次数最多的成为该元素的重数, 多重集合S重 ...
- Oracle怎么用(常用工具)
Oracle数据库管理系统装好了!那要怎么用呢? 将介绍的工具:①Database Configuration Assistant ②SQL Plus ③SQL Developer 一.Dat ...
- [Vue @Component] Switch Between Vue Components with Dynamic Components
A common scenario is to present different components based on the state of the application. Dynamic ...
- duilib中加入自己定义控件之后怎么可以在xml文件里配置使用
加入自己定义控件可能有两种不同的情况: 1. 在duilib库中加入的自己定义控件. 2. 在我们的应用程序中自己重写了一个控件. 以下開始解说不同的情况下怎么才干支持在xml文件配置控件: 1. ...
- android 通过子线程跳转activity并传递内容
android 子线程中不能够更新ui已经根深蒂固在我的脑海里,当时也就理所当然的觉得子线程中也是不能够进行界面的跳转的,可是在后来的学习中,发现居然是能够通过子线程来进行activity的跳转时,立 ...
- iOS开发之剖析"秘密"App内容页面效果(一)
近期在玩"秘密",发现点击主界面的Cell进去后的页面效果不错,就写了个Demo来演示下. 它主要效果:下拉头部视图放大,上拉视图模糊并且到一定位置固定不动,其它Cell能够继续上 ...
- jsoncpp的生成和使用
从github下载jsoncpp-master 在执行\jsoncpp-master\makefiles\msvc2010文件夹下jsoncpp.sln 会有3个项目 执行lib_json项目生成li ...
- HDOJ 4705 Y 树形DP
DP:求出3点构成链的方案数 .然后总方案数减去它 Y Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K ...
- POJ 3683 Priest John's Busiest Day (2-SAT+输出可行解)
题目地址:POJ 3683 第一次做须要输出可行解的题目. . .大体思路是先用强连通来推断是否有可行解,然后用逆序建图.用拓扑排序来进行染色.然后输出可行解. 详细思路见传送门 由于推断的时候少写了 ...
- kafka01
消息队列松耦合 消息队列