【NOIP2014 提高组】

DAY1

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

就直接模拟

#include<bits/stdc++.h>
using namespace std;
int n,na,nb,win_a,win_b;
int a[201],b[201];
bool jud[6][6];
void Judge(int x,int y){
	if(x == y) return;
	if(jud[x][y] == 1) win_a++;
		else win_b++;
	return;
}
int main()
{
//	freopen("rps.in","r",stdin);
//	freopen("rps.out","w",stdout);
	jud[1][3]=jud[1][4]=jud[2][1]=jud[2][4]=jud[3][2]=1;
	jud[3][5]=jud[4][3]=jud[4][5]=jud[5][1]=jud[5][2]=1;
	scanf("%d %d %d ",&n,&na,&nb);
	for(int i=1; i<=na; i++) scanf("%d",&a[i]),a[i]++;
	for(int i=1; i<=nb; i++) scanf("%d",&b[i]),b[i]++;
	int ia=0,ib=0;
	while(n--){
		ia = ia==na ? 1 : ia+1;
		ib = ib==nb ? 1 : ib+1;
		Judge(a[ia],b[ib]);
	}
	printf("%d %d",win_a,win_b);
	return 0;
}

T2 联合权值

考场读题直接把图认为成了一条链,鸭蛋
正解:

  • 思路:对于当前点i,联合权值即为i左右两边点的乘积!
  • 第一问:最大值,即为i点两边的前2大点的乘积
  • 第二问:总和,变形即为点值和的平方—各个点的平方!
    AC码子
#include<bits/stdc++.h>
using namespace std;
#define N 200001
#define mod 10007
long long l,m,n;
long long kao[N];
vector <long long>ha[N];
int main(){
	scanf("%lld",&n);
	for(long long z=1; z<n; z++){
    	long long x,y;
		scanf("%lld %lld",&x,&y);
		ha[x].push_back(y);
		ha[y].push_back(x);
	}
	for(long long z=1; z<=n; z++) scanf("%lld",&kao[z]);
	for(long long z=1; z<=n; z++){
		long long cal1=0,m1=0,m2=0;
		for(long long y=0; y<ha[z].size(); y++){
			long long x = ha[z][y];
			cal1 += kao[x];
			l -= kao[x]*kao[x];
			if(kao[x]>m2){
				if(kao[x]>m1){
					m2 = m1;
					m1 = kao[x];
				}
				else m2 = kao[x];
			}
		}
		l += cal1*cal1; l %= mod;
		m = max(m,m1*m2);
	}
	printf("%lld %lld",m,l);
	return 0;
}

T3 飞扬的小鸟

70分,直接模拟+DP,注意无柱子均可以飞,到最高只能达到m

#include<bits/stdc++.h>
using namespace std;
#define N 10001
int n,m,k,sum;
int f[N][1001],dis[N][2],g[N][2];
bool Can_exist(int y,int i){
	if(y > g[i][0]){
		if(g[i][1] == 0)return true;
		if(y < g[i][1]) return true;
	}
	return false;
}
int main()
{
//	freopen("bird.in","r",stdin);
//	freopen("bird.out","w",stdout);
	scanf("%d %d %d",&n,&m,&k);
	for(int i=0; i<=n-1; i++) scanf("%d %d",&dis[i][1],&dis[i][0]);
	for(int i=1; i<=k; i++){
		int t,x,y;
		scanf("%d %d %d",&t,&x,&y);
		g[t][0] = x;
		g[t][1] = y;
	}
	memset(f,0x3f,sizeof(f));
	for(int i=0; i<=m; i++) f[0][i] = 1;
	
	for(int i=0; i<=n-1; i++){
		bool find = false;
		for(int j=0; j<=m; j++){
			if(f[i][j]!=1061109567){
				//down
				int down = j - dis[i][0];
				if(Can_exist(down,i+1)){
					find = true;
					f[i+1][down] = min(f[i+1][down],f[i][j]);
				}
				//up
				int up=0;
				for(int t=1; 1; t++){
					up = j+t*dis[i][1];
					if(Can_exist(up,i+1)){
						find = true;
						int up2 = up>m ? m : up;
						f[i+1][up2] = min(f[i+1][up2],f[i][j]+t);
					}else break;
					if(up > m) break;
				}
			}
		}
		if(find == false){
			int ans=0;
			for(int j=1; j<=i; j++)
			if(g[j][0] || g[j][1]) ans++;
			printf("0\n%d",ans);
			return 0;
		}
	}
	int ans = 99999999;
	for(int i=0; i<=m; i++) ans = min(ans,f[n][i]);
	printf("1\n%d",ans-1);
	return 0;
}

~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DAY2

T1 无线网络发射器选址

直接枚举每个方形的中点,但是要注意四边范围,中点可以是棋盘任何位置!!!
(考试我没注意j的范围WA了3个点)
满分

#include<bits/stdc++.h>
using namespace std;
int d,n,maxn,sum;
int a[130][130],pre[130][130];
int main()
{
//	freopen("wireless.in","r",stdin);
//	freopen("wireless.out","w",stdout);
	scanf("%d\n%d",&d,&n);
	int x,y,z;
	for(int i=1; i<=n; i++){
		scanf("%d%d%d",&x,&y,&z);
		pre[x][y] = a[x][y] = z;
	}
	for(int i=0; i<=128; i++)
	for(int j=0; j<=128; j++)
		pre[i][j] += pre[i][j-1];
	for(int i=0; i<=128; i++)
	for(int j=0; j<=128; j++){
		int tot = 0;
		int si = i-d>0?i-d:0,	 sj = j-d>0?j-d:0;
		int ei = i+d<128?i+d:128,ej = j+d<128?j+d:128;
		for(int i2=si; i2<=ei; i2++)
			tot += (pre[i2][ej]-pre[i2][sj]+a[i2][sj]);
		if(tot>maxn){
			maxn = tot;
			sum = 1;
		}else if(tot == maxn) sum++;
	}
	printf("%d %d",sum,maxn);
	return 0;
 } 

T2 寻找道路

考场暴力 10分

正解:

  1. 反向制表
  2. 从终点BFS,标记可以搜到的点,其他搜不到的后面则不选择作为路径
    3. SPFA模板!!!

可爱的 代码

#include<bits/stdc++.h>
using namespace std;
int ct,s,t;
int used[300000],dis[300000],vis[300000],head[500000];
int n,m,x[300000],y[300000];
bool flag;
struct edge{
	int next,to;
}e[500000];
void add(int from,int to){
	e[++ct].to=to;
	e[ct].next=head[from];
	head[from]=ct;
	return;
}
bool pd(int pos){
   		for(int i=head[pos];i;i=e[i].next)
		if(!used[e[i].to]) return 0;
    return true;
}
void BFS(){
	queue<int>q;
	q.push(t);used[t]=1;
	while(!q.empty()){
    	int pos=q.front();q.pop();
    	for(int i=head[pos];i;i=e[i].next){
        	if(!used[e[i].to]){
                q.push(e[i].to);
            	used[e[i].to]=1;
        	}
		}
	}
 }
 void SPFA()
 {
    queue<int> q;
    q.push(s);dis[s]=0;vis[s]=1;
	while(!q.empty()){
		int p=q.front();vis[p]=0;q.pop();
		if(pd(p)==0) continue;
		for(int i=head[p];i;i=e[i].next){
            int v=e[i].to;
            if(dis[v]>dis[p]+1){
            	dis[v]=dis[p]+1;
                if(!vis[v]){
            		q.push(v);
					vis[v]=1;
            	}
            	if(v==t){ flag=true; }
        	}
		}
	}
 }
 int main()
 {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x[i],&y[i]);
		add(y[i],x[i]); 
    }
    scanf("%d%d",&s,&t);
    BFS();
	if(!used[s]){//spj
        printf("-1");
		return 0;
    }
    memset(head,0,sizeof(head));
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
    ct=0;
    for(int i=1;i<=m;i++)
        add(x[i],y[i]);
	SPFA();
    if(flag==false) printf("-1");
    	else printf("%d",dis[t]);
    return 0;
}

T3 解方程

考试的时候想到秦九韶(即不断提取公因式x,简化系数),但是不知道对an这么大的数怎么处理····
正解:咋处理an?让我们膜它! 可以发现:f(x)%质数==0则x是一个解!

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template <typename _Tp> inline void read(_Tp &x){
    char c11=getchar();x=0;bool booo=0;
    while(c11<'0'||c11>'9'){if(c11=='-')booo=1;c11=getchar();}
    while(c11>='0'&&c11<='9'){x=(x*10+c11-'0')%mod;c11=getchar();}
    if(booo)x=-x;
    return ;
}
const int maxn=101;
ll a[maxn];int st[1000005],p=0;
int n,m;
inline bool check(int x){
    ll sum=0;
    for(int i=n;i>-1;--i)
        sum=((a[i]+sum)*x)%mod;//秦九韶!!!!!(即不断提公因式x) 
    return sum==0;
}
void work(){
    for(int i=1;i<=m;++i)if(check(i))st[++p]=i;
    check(65536);
    printf("%d\n",p);for(int i=1;i<=p;i++)printf("%d\n",st[i]);
    return ;
}
void init(){
    read(n);read(m);
    for(int i=0;i<=n;++i) read(a[i]);
}
int main(){
    init();
    work();
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值