[noip][2017]
Day1T1
30分思路:
倒着枚举答案z,用扩展欧几里得求解,如果能找到两个非负整数x,y使得ax+by=z则继续枚举,直到无解为止
100分:
最适用与考场上的做法,根据30分思路打表找规律。
30分代码:
#include<cstdio>
#include<iostream>
using namespace std;
#define int long long
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1;y=0;
return a;
}
int t=exgcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-a/b*y;
return t;
}
inline int cei(int x,int y)
{
return x%y==0?x/y:x/y+1;
}
main()
{
int n,m,x,y;
cin>>n>>m;
exgcd(n,m,x,y);
for(int i=10000000;i>1;--i)
{
int xx=x*i,yy=y*i;
if(xx>=0&&yy>=0)
continue;
if(xx<0&&yy>=0)
{
int z=cei(-xx,m);
if(yy-z*n<0)
{
printf("%lld",i);
return 0;
}
else continue;
}
if(yy<0&&xx>=0)
{
int z=cei(-yy,n);
if(xx-z*m<0)
{
printf("%lld",i);
return 0;
}
else continue;
}
}
return 0;
}
100分代码:
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
int main()
{
ll n,m;
cin>>n>>m;
cout<<n*m-n-m;
return 0;
}
Day1T2
思路
虽然这个题就是模拟,但是坑点还是比较多的,如果不好好读题目就很容易炸掉。首先,对于初始变量大于终止变量的不能进入循环。如果初始变量和终止变量都是n那么算作常数复杂度。ERR优先于NO。然后慢慢地一边打注释一边模拟就好了。
代码
#include<cstdio>
#include<iostream>
#include<string>
#include<map>
#include<cstring>
using namespace std;
int t;
string s;
map<char,int>ma;
int read(string c)
{
int x=0;
int len=c.size();
for(int i=0;i<len;++i)
{
if(!isdigit(c[i])) continue;
x=x*10+c[i]-'0';
}
return x;
}
int read1(char x[])
{
int b=0;
int len=strlen(x)-1;
for (int i = 0; i <=len ; ++i)
if(isdigit(x[i])) b=b*10+x[i]-'0';
return b;
}
char zhan[110];
char cc[3],c[3];
int pdn[110];
int main()
{
// freopen("1.in","r",stdin);
scanf("%d",&t);
while(t--)
{
int w=0,L,bz=1,njs=0,ansbz=0,nmax=0,pdjs=0,top=0,tcbz=-1;
ma.clear();
scanf("%d",&L);
cin>>s;
if(s=="O(1)")bz=0;//0表示O(1)复杂度,1表示n^w复杂度
else w=read(s);
while(L--)
{
cin>>c;
if(c[0]=='F')
{
cin>>c;
zhan[++top]=c[0];//记录变量
if(ma[c[0]]==1) //判断是不是重名
ansbz=1;//ansbz为1答案为'ERR'
ma[c[0]]=1;
cin>>c;
cin>>cc;
if(((cc[0]!='n'&&c[0]!='n'&&read1(cc)<read1(c))||(c[0]=='n'&&cc[0]!='n'))&&(tcbz==-1))
tcbz=pdjs;
if(cc[0]=='n'&&c[0]!='n')
{
pdn[++pdjs]=1;//1表示为n,2表示为1
if(tcbz==-1)
{
njs++;
nmax=max(nmax,njs);
if(bz==0&&ansbz!=1)
ansbz=2;//ansbz为2答案为'No'
}
}
else
pdn[++pdjs]=2;
}
else//循环结束
{
ma[zhan[top]]=0;//销毁变量
top--;
if(tcbz==-1)
{
if(pdn[pdjs]==1)//将复杂度减去
njs--;
}
pdjs--;//当前层数--
if(pdjs==tcbz) tcbz=-1;
}
}
if(top!=0) ansbz=1;
if(ansbz==1)
{
printf("ERR\n");
continue;
}
if(w!=nmax) ansbz=2;
if(ansbz==2)
{
printf("No\n");
continue;
}
printf("Yes\n");
}
return 0;
}
Day1T3
30分思路
对于所有k=0的情况就是找最短路的条数,只要再找最短路的时候加一个判断就行了
100分思路
首先明显是dp,设f[i][k]表示到第i个点,路线长度与最短路差的绝度值不超过k的方案数。那么对于一条边u->v转移方程就是f[v][k]+=f[u][dis[v]+k-w-dis[u]],但是必须要求u先被更新完了才能去更新v,拓扑排序又有环,所以考虑记忆化搜索,f(v,k)表示与上方数组相同的含义,只是这时的v变成了u,u变成了v。
30分代码
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
const int N=100000*5+100,M=200000*5+100;
typedef pair<int,int> pi;
typedef long long ll;
int T,dis[N],mod,in[N],n,m,K;
struct node
{
int v,nxt,w;
node()
{
v=0,nxt=0,w=0;
}
}e[N];
int ejs,head[N],vis[N];
int qq[N];
void add(int u,int v,int w)
{
e[++ejs].v=v;e[ejs].w=w;e[ejs].nxt=head[u];head[u]=ejs;
}
int ans[N];
priority_queue<pi,vector<pi>,greater<pi> > q;
void dijkstral()
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
dis[1]=0;
q.push(make_pair(dis[1],1));
for(int i=1;i<=n;++i)
{
while(vis[q.top().second]==1&&!q.empty()) q.pop();
int u=q.top().second;
vis[u]=1;
ans[1]=0;
for(int j=head[u];j;j=e[j].nxt)
{
int v=e[j].v;
if(dis[v]>dis[u]+e[j].w)
{
dis[v]=dis[u]+e[j].w;
q.push(make_pair(dis[v],v));
ans[v]=1;
}
else if(dis[v]==dis[u]+e[j].w)
{
ans[v]+=ans[u];
}
}
}
}
ll f[N][55];
int main()
{
scanf("%d",&T);
while(T--)
{
ejs=0;
memset(ans,0,sizeof(ans));
memset(head,0,sizeof(head));
scanf("%d%d%d%d",&n,&m,&K,&mod);
for(int i=1;i<=m;++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
dijkstral();
cout<<ans[n]<<endl;
}
return 0;
}
100分代码
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
const int N=100100,M=200010;
int n,m,K,t,ejs,mod,flag;
int head[N],dis[N],vis[N];
int f[N][60],bz[N][60];
queue<int>q;
struct node{
int u,v,w,nxt;
}e[M];
void add(int u,int v,int w) {
e[++ejs].u=u;e[ejs].v=v;e[ejs].w=w;e[ejs].nxt=head[u];head[u]=ejs;
}
void spfa() {
while(!q.empty()) q.pop();
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[1]=0;
q.push(1);
while(!q.empty()) {
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w) {
dis[v]=dis[u]+e[i].w;
if(!vis[v]) {
q.push(v);
vis[v]=1;
}
}
}
}
}
int dfs(int u,int k) {
if(bz[u][k]==1||flag==1) return flag=1;
if(bz[u][k]==2) return f[u][k];
bz[u][k]=1;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
int w=k+dis[u]-dis[v]-e[i].w;
if(w>K||w<0) continue;
f[u][k]+=dfs(v,w);
f[u][k]%=mod;
}
bz[u][k]=2;
return f[u][k];
}
int main() {
scanf("%d",&t);
while(t--) {
ejs=0;
memset(head,0,sizeof(head));
scanf("%d%d%d%d",&n,&m,&K,&mod);
for(int i=1,x,y,z;i<=m;++i) {
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
spfa();
memset(head,0,sizeof(head));
for(int i=1;i<=m;++i) {
swap(e[i].v,e[i].u);
e[i].nxt=head[e[i].u];
head[e[i].u]=i;
}
memset(f,0,sizeof(f));
memset(bz,0,sizeof(bz));
flag=0;
f[1][0]=1;
int ans=0;
for(int i=0;i<=K;++i) {
ans+=dfs(n,i);
ans%=mod;
if(flag==1){
ans=-1;
break;
}
}
printf("%d\n",ans);
}
return 0;
}
Day2T1
思路
先\(n^2\)连边,然后从底下开始bfs看能不能搜到上面。
代码
#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
using namespace std;
const int N=1010;
double n,h,R;
int S,T;
queue<int>q;
struct poin {
double x,y,z;
}p[N];
inline int ab(double x) {
return x>=0?x:-x;
}
struct node {
int v,nxt;
}e[N*N];
int ejs,head[N],vis[N];
void add(int u,int v) {
e[++ejs].v=v;e[ejs].nxt=head[u];head[u]=ejs;
}
inline int check(int x,int y) {
return (p[x].x-p[y].x)*(p[x].x-p[y].x)+(p[x].y-p[y].y)*(p[x].y-p[y].y)+(p[x].z-p[y].z)*(p[x].z-p[y].z)<=R*R*4;
}
int bfs() {
while(!q.empty()) q.pop();
memset(vis,0,sizeof(vis));
q.push(S);
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(!vis[v]) {
q.push(v);
vis[v]=1;
}
}
}
return vis[T];
}
int main() {
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--) {
ejs=0;
memset(head,0,sizeof(head));
cin>>n>>h>>R;
T=n+1,S=0;
for(int i=1;i<=n;++i) {
cin>>p[i].x>>p[i].y>>p[i].z;
if(ab(p[i].z)<=R) add(S,i);
if(ab(p[i].z-h)<=R) add(i,T);
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(check(i,j)&&i!=j) add(i,j),add(j,i);
if(bfs())
printf("Yes\n");
else printf("No\n");
}
return 0;
}
Day2T2
40分思路
对于所有v相等的情况,只要floyd一遍找出最短路。然后枚举起始点找最小花费即可。
100分思路
100分可以状态压缩,但是还是看了一骗模拟退火的题解。就是在进行prim的过程中,随机的选次优点进行更新。然后多进行几遍找出最优方案即可。
40分代码
#include<cstdio>
#include<cstring>
#include<iostream>
const int N=30;
using namespace std;
int f[N][N];
int main() {
int n,m,Z;
scanf("%d%d",&n,&m);
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;++i)
f[i][i]=0;
for(int i=1;i<=m;++i) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
Z=z;
f[x][y]=f[y][x]=1;
}
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(f[i][j]>f[i][k]+f[k][j])
f[i][j]=f[i][k]+f[k][j];
int anss=0x7fffffff;
for(int i=1;i<=n;++i) {
int ans=0;
for(int j=1;j<=n;++j)
ans+=f[i][j];
anss=min(anss,ans);
}
printf("%d",anss*Z);
return 0;
}
100分代码
#include<cstdlib>
#include<ctime>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=20,INF=10000000;
int vis[N],a[N][N],dis[N];
int n,m;
struct node {
int u,v;
};
bool operator < (const node &x,const node &y) {
return dis[x.u]*a[x.u][x.v]>dis[y.u]*a[y.u][y.v];
}
priority_queue<node> q;
int prim(int S) {
int ans=0;
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
int js=0;
node ls[N*N];
node k;
dis[S]=1;
vis[S]=1;
while(!q.empty()) q.pop();
for(int i=1;i<=n;++i) {//先找到S可以更新的点
if(a[S][i]<INF){
node e;
e.u=S,e.v=i;
q.push(e);
}
}
for(int i=1;i<n;++i) {
k=q.top();q.pop();
while(!q.empty()&&(vis[k.v]||rand()%n<1)) {//找到要用来更新的边
if(!vis[k.v]) ls[++js]=k;
k=q.top();
q.pop();
}
vis[k.v]=1;
dis[k.v]=dis[k.u]+1;//更新v
//printf("%d\n",dis[k.u]);
ans+=dis[k.u]*a[k.u][k.v];//加入生成树
while(js)//将预存的边加入队列
q.push(ls[js--]);
for(int j=1;j<=n;++j) {
if(a[k.v][j]<INF&&!vis[j]) {//扩展更多的边
node e;
e.u=k.v;
e.v=j;
q.push(e);
}
}
}
return ans;
}
int main() {
srand(time(0));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
a[i][j]=INF;
for(int i=1;i<=m;++i) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
a[x][y]=a[y][x]=min(a[x][y],z);
}
int ans=INF;
for(int i=1;i<=1000;++i)
for(int j=1;j<=n;++j)
ans=min(ans,prim(j));
printf("%d",ans);
return 0;
}
Day2T3
思路##
还是只会30分模拟思路。
30分代码
#include<cstdio>
#include<iostream>
using namespace std;
const int N=1010;
int q,a[N][N],n,m;
inline void change(int x,int y) {
int tmp=a[x][y];
for(int i=y;i<m;++i)
a[x][i]=a[x][i+1];
for(int i=x;i<n;++i)
a[i][m]=a[i+1][m];
a[n][m]=tmp;
}
int main() {
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=(i-1)*m+j;
while(q--) {
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",a[x][y]);
change(x,y);
}
return 0;
}
总结
noip2017题目比较难,但是暴力只要打满了分数还是可观的。day1的暴力分有30+100+30=160。day2有100+40+30=170。这就有330分了,即便day1t2写挂了只要能拿到30分,就还是能拿到一等奖的(260)。所以打好暴力很重要。。
[noip][2017]的更多相关文章
- NOIP 2017 解题报告
---恢复内容开始--- NOIP 2017 的题真的很难啊,怪不得当年我这个萌新爆零了(当然现在也是萌新)越学越觉得自己什么都不会. 想要成为强者要把这些好题都弄懂弄透 至少现在6道题我都比较陌生 ...
- NOIP 2017 列队 - Splay - 树状数组
题目传送门 传送点I 传送点II 题目大意 (家喻户晓的题目应该不需要大意) (我之前咋把NOIP 2017打成了NOIP 2018,好绝望) Solution 1 Splay 每行一颗Splay,没 ...
- 【游记】NOIP 2017
时间:2017.11.11~2017.11.12 地点:广东省广州市第六中学 Day1 T1:看到题目,心想这种题目也能放在T1? 这个结论我之前遇到过至少3次,自己也简单证明过.初见是NOIP200 ...
- NOIP 2017 小凯的疑惑
# NOIP 2017 小凯的疑惑 思路 a,b 互质 求最大不能表示出来的数k 则k与 a,b 互质 这里有一个结论:(网上有证明)不过我是打表找的规律 若 x,y(设x<y) 互质 则 : ...
- 历年真题 未完成(Noip 2008 - Noip 2017)
Noip 2008 :全部 Noip 2009 :全部 Noip 2010 :AK Noip 2011 :AK Noip 2012 : Vigenère 密码,国王游戏,开车旅行 Noip 2013 ...
- 「NOIP 2017」列队
题目大意:给定一个 $n times m$ 的方阵,初始时第 $i$ 行第 $j$ 列的人的编号为 $(i-1) times m + j$,$q$ 次给出 $x,y$,让第 $x$ 行 $y$ 列的人 ...
- 洛谷 P3951 NOIP 2017 小凯的疑惑
洛谷 P3951 NOIP 2017 小凯的疑惑 题目描述 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有 无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付 ...
- NOIP 2017 提高组 day1t2 时间复杂度
P3952 时间复杂度 标签 NOIp提高组 2017 时空限制 1000ms / 128MB 小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂 ...
- [日常] NOIP 2017滚粗记
突然挑了这么个滑稽的时间补了游记... (成绩日常延时再加上人太菜估计基本上就是颓废记录) 然而文化课太废可能会被强制退役QAQ所以先补了再说吧 day0 一大早被老姚交代了个开十一机房门的任务... ...
- [NOIp 2017]列队
Description Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有$n \times m$名学生, ...
随机推荐
- 浅谈nornalize.css(含源码)
Normalize.css是一种CSS reset的替代方案.经过@necolas和@jon_neal花了几百个小时来努力研究不同浏览器的默认样式的差异,这个项目终于变成了现在这样. 我们创造norm ...
- Nginx基于TCP/UDP端口的四层负载均衡(stream模块)配置梳理
通过我们会用Nginx的upstream做基于http/https端口的7层负载均衡,由于Nginx老版本不支持tcp协议,所以基于tcp/udp端口的四层负载均衡一般用LVS或Haproxy来做.至 ...
- back
#include<stdio.h> int main() { int a[5],b[5][5]; int i,j,sum,max,m,n; printf("输 ...
- 基础-Math.floor与parseInt区别
Math.floor只能对一个数向下取整,不能解析字符串 如: Math.floor(1.5) // 1 Math.floor(-2.1) // -3 Math.floor("3" ...
- 实验十一 团队作业7—团队项目设计完善&编码测试
实验十一 团队作业7—团队项目设计完善&编码测试 实验时间 2018-6-8 Deadline: 2018-6-20 10:00,以团队随笔博文提交至班级博客的时间为准. 评分标准: 按时交 ...
- JavaScript解决一个带验证的Form两个Submit事件(一个页面保持不动【AJAX实现】,一个页面提交并跳转)的场景
<form class="form-horizontal" action="/biz/patent/edit" method="post&quo ...
- Activiti动态设置办理人扩展
关键词:Assignee.Candidate users.Candidate groups:setAssignee.taskCandidateUser.taskCandidateGroup 主要解决问 ...
- DVWA的安装与简单使用
参考资料: http://www.freebuf.com/articles/web/119150.html 尝试使用linux机器安装,但是因为下载php版本以及各种兼容性的问题耗时较长, 所以后来选 ...
- Python表达式与运算符
表达式与运算符 Python语言支持以下类型的运算符: 算术运算符 比较(关系)运算符 赋值运算符 逻辑运算符 位运算符 成员运算符 身份运算符 运算符优先级 算术运算符 运算符 描述 + 加 - 两 ...
- cmd常用
npm install -g npm npm就自动为我们更新到最新版本 npm install -g cnpm --registry=https://registry.npm ...