NOIP2013题解+总结

Day1

T1 水题,快速幂

#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
class DREAD{
	public:
		int Int(){ int x;read(x);return x; }
	private:
		bool isdigit(char ch){ return ('0'<=ch && ch<='9'); }
		void read(int &x){
			char ch;bool pos=1;x=0;
			while (ch=getchar())
				if (isdigit(ch) || ch=='-'){
					if (ch=='-') ch=getchar(),pos=0;
					break;
				}
			for (; isdigit(ch); ch=getchar()) x=x*10+ch-'0';
			if (!pos) x=-x;
		}
}READ;
int N,M,K,X;
LL power(LL a,int b){
	if (!b) return 1;
	if (b==1) return a;
	LL tmp=power(a,b/2);
	tmp=((tmp%N)*(tmp%N))%N;
	if (b%2==0) return tmp; else return (tmp*a)%N;
}
int main(){
	N=READ.Int(),M=READ.Int(),K=READ.Int(),X=READ.Int();
	LL tmp=power(10,K);
	tmp%=N;
	cout<<(X+(tmp*(LL)M)%N)%N<<endl;
	return 0;
}

T2排序求逆序对,本来考场上已经往这方面想了,但是最后还是没写写了个60分暴力结果挂了,正解代码:

#include<cstdio>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
#define MP make_pair
class DREAD{
	public:
		int Int(){ int x;read(x);return x; }
	private:
		bool isdigit(char ch){ return ('0'<=ch && ch<='9'); }
		void read(int &x){
			char ch;x=0;
			while (ch=getchar()) if (isdigit(ch)) break;
			for (; isdigit(ch); ch=getchar()) x=x*10+ch-'0';
		}
}READ;
template <typename Type> class T_SUM_BIT{
	/*--BIT->Binary Indexed Tree--*/
	public:
		static const int SIZE=100000+10;
		Type t[SIZE],sum[SIZE];
		int real_size;
		void Init(int size){ real_size=size; }
		void Build(int size){
			real_size=size;
			for (int i=1; i<=real_size; ++i) t[i]=sum[i]-sum[i-lowbit(i)];
		}
		void Modify(int idx,int delta){
			for (int p=idx; p<=real_size; p+=lowbit(p)) t[p]+=delta;
		}
		Type Query(int idx){
			Type res=0;
			for (int p=idx; p; p-=lowbit(p)) res+=t[p];
			return res;
		}
	private:
		int lowbit(int idx){ return idx&-idx; }
};
class PROGRAM{
	public:
		void Open(){ freopen("data.in","r",stdin); }
		void Init(){
			N=READ.Int();
			for (int i=1; i<=N; ++i) a[i].first=READ.Int(),a[i].second=i;
			for (int i=1; i<=N; ++i) b[i].first=READ.Int(),b[i].second=i;
		}
		void Work(){
			sort(a+1,a+N+1);sort(b+1,b+N+1);
			for (int i=1; i<=N; ++i) rank[b[i].second]=a[i].second;
			bit.Init(N);int res=0;
			for (int i=N; i>=1; --i){
				res+=bit.Query(rank[i]-1);res%=mod;
				bit.Modify(rank[i],1);
			}
			printf("%d\n", res%mod);
		}
	private:
		static const int N_MAX=100000+10,mod=99999997;
		int N,rank[N_MAX];PII a[N_MAX],b[N_MAX];
		T_SUM_BIT<int> bit;
}PROG;
int main(){
	//PROG.Open();
	PROG.Init();
	PROG.Work();
	return 0;
}

T3最大生成树+LCA,考场上没想出来,写的暴力挂掉了,正解代码:

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define it(type) vector<type>::iterator
class DREAD{
	public:
		int Int(){ int x;read(x);return x; }
	private:
		bool isdigit(char ch){ return '0'<=ch && ch<='9'; }
		void read(int &x){
			char ch;x=0;
			while (ch=getchar()) if (isdigit(ch)) break;
			for (; isdigit(ch); ch=getchar()) x=x*10+ch-'0';
		}
}READ;
struct Tedge{
	int a,b,c;
	Tedge(){}
	Tedge(int _a,int _b,int _c):a(_a),b(_b),c(_c){}
};
bool cmp_edge(const Tedge &a,const Tedge &b){ return a.c>b.c; }
vector<Tedge> edge;
const int N_MAX=10000+10,M_MAX=100000+10,K_MAX=15,inf=~0u>>1;
int N,M;
void Init(){
	N=READ.Int();M=READ.Int();
	for (int i=1; i<=M; ++i){
		int a=READ.Int(),b=READ.Int(),c=READ.Int();
		edge.push_back(Tedge(a,b,c));
	}
}
int now[N_MAX],pre[M_MAX],son[M_MAX],v[M_MAX],tot=0;bool vis[N_MAX];
inline void add(int a,int b,int c){ pre[++tot]=now[a];now[a]=tot;son[tot]=b;v[tot]=c; }
inline void con(int a,int b,int c){ add(a,b,c);add(b,a,c); }
int fa[N_MAX];
int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); }
void Kruscal(){
	sort(edge.begin(),edge.end(),cmp_edge);
	for (int i=1; i<=N; ++i) fa[i]=i;
	int select=0;
	for (it(Tedge) i=edge.begin(); i!=edge.end(); ++i){
		int x=find(i->a),y=find(i->b);
		if (x==y) continue;
		fa[x]=y;con(x,y,i->c);
		if (++select==N-1) return;
	}
}
struct Tmultiple{
	int anc,min;
	Tmultiple(){}
	Tmultiple(int _anc,int _min):anc(_anc),min(_min){}
}mul[N_MAX][K_MAX];
int dep[N_MAX];
void Dfs(int x){
	vis[x]=1;
	for (int p=now[x]; p; p=pre[p])
		if (!vis[son[p]]){
			dep[son[p]]=dep[x]+1;
			mul[son[p]][0]=Tmultiple(x,v[p]);
			for (int i=1; i<K_MAX; ++i){
				mul[son[p]][i].anc=mul[mul[son[p]][i-1].anc][i-1].anc;
				mul[son[p]][i].min=min(mul[son[p]][i-1].min,mul[mul[son[p]][i-1].anc][i-1].min);
			}
			Dfs(son[p]);
		}
}
int Answer(int a,int b){
	if (find(a)!=find(b)) return -1;
	int res=inf;
	if (dep[a]<dep[b]) swap(a,b);
	for (int i=K_MAX-1; i>=0; --i)
		if (dep[a]-(1<<i)>=dep[b]){
			res=min(res,mul[a][i].min);
			a=mul[a][i].anc;
		}
	for (int i=K_MAX-1; i>=0; --i)
		if (mul[a][i].anc!=mul[b][i].anc){
			res=min(res,min(mul[a][i].min,mul[b][i].min));
			a=mul[a][i].anc;b=mul[b][i].anc;
		}
	if (a!=b) return res=min(res,min(mul[a][0].min,mul[b][0].min));
	return res;
}
void Solve(){
	Kruscal();memset(vis,0,sizeof(vis));
	for (int i=1; i<=N; ++i)
		if (!vis[i]){
			dep[i]=0;
			Dfs(i);
		}
	int Q=READ.Int();
	for (int i=1; i<=Q; ++i){
		int a=READ.Int(),b=READ.Int();
		printf("%d\n", Answer(a,b));
	}
}
int main(){
	Init();
	Solve();
	return 0;
}


-------------------------------------分割线------------------------------------------

Day1总结:考场上写第二题的时候有点乱,想的时候脑子一团糟,最后写了个60分的暴力,为了写第三题自己生了两组小数据后就没check了,结果昨天测了民间数据后发现暴力挂了,丢了60分,十分不爽。第三题考场上没想出来,也没check,再丢60。。。。。。如果第一天有220,那省一就毫无压力了。Day1的惨痛经历告诉我,不要过分相信自己的感觉,在考场上一定要稳,既然写了部分分,就一定要拿到,如果考完了发现部分分挂了,那还不如用写部分分的时间想正解。

-------------------------------------分割线-------------------------------------------

Day2

T1是USACO2013MAR的原题Poker Hands,考前做过一遍,结果考场上没想起来,70分暴力幸好没挂正解代码:

#include<cstdio>
using namespace std;
inline bool isdigit(char ch){return ('0'<=ch && ch<='9');}
inline int read(){
	char ch;int tmp=0;
	while (ch=getchar()) if (isdigit(ch)) break;
	for (; isdigit(ch); ch=getchar()) tmp=tmp*10+ch-'0';
	return tmp;
}
inline void write(int &ans){
	char ch[9];int tot=0;
	while (ans) ch[++tot]=ans%10+'0',ans/=10;
	for (int i=tot; i>=1; --i) putchar(ch[i]);
	puts("");
}
int main(){
	int n=read(),ans=0;
	for (int i=1,num=0,pre=0; i<=n; ++i,pre=num){
		num=read();
		if (num>pre) ans+=num-pre;
	}
	write(ans);
	return 0;
}
T2贪心或者线段树优化DP,我考场上写的是贪心,直接O(n)取出每个单调区间的最高点和最低点再求答案

#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
#define MP make_pair
class DREAD{
	public:
		int Int(){ int x;read(x);return x; }
	private:
		bool isdigit(char ch){ return ('0'<=ch && ch<='9'); }
		void read(int &x){
			char ch;bool pos=1;x=0;
			while (ch=getchar())
				if (ch=='-' || isdigit(ch)){
					if (ch=='-') ch=getchar(),pos=0;
					break;
				}
			for (; isdigit(ch); ch=getchar()) x=x*10+ch-'0';
			if (!pos) x=-x;
		}
}READ;
const int N_MAX=100000+10;
int N,a[N_MAX];
struct Tseg{
	int first,second,flag;
	Tseg(){}
	Tseg(int _first,int _second,int _flag):first(_first),second(_second),flag(_flag){}
};
vector<Tseg> vec;
enum Ttype{DEC,INC};
int DOA(){
	int res=1;
	if (vec[0].flag==DEC) res+=vec.size()-1;
	else res+=vec.size();
	return res;
}
int DOB(){
	int res=1;
	if (vec[0].flag==INC) res+=vec.size()-1;
	else res+=vec.size();
	return res;
}
int main(){
	N=READ.Int();
	if (N==1){ puts("1");return 0; }
	if (!N){ puts("0");return 0; }
	for (int i=1; i<=N; ++i) a[i]=READ.Int();
	int BP;
	for (int i=1; i<=N; ++i) if (a[i]!=a[i+1]){
		BP=i;
		break;
	}
	int flag=(a[BP+1]>a[BP]),L=1,R;
	for (int i=BP+2; i<=N; ++i){
		if (flag){
			if (a[i]<a[i-1]){
				flag=DEC;
				vec.push_back(Tseg(L,i-1,INC));
				L=i-1;
			}
		}
		else{
			if (a[i]>a[i-1]){
				flag=INC;
				vec.push_back(Tseg(L,i-1,DEC));
				L=i-1;
			}
		}
	}
	if (L!=N) vec.push_back(Tseg(L,N,flag));
	int res1=DOA(),res2=DOB();
	printf("%d\n", res1>res2?res1:res2);
	return 0;
}
T3对正解不明觉厉,直接乱搞,不知道多少分。。。

-------------------------------------分割线-----------------------------------------

Day2总结:Day2比Day1考的要好一些,虽然第一题没想到正解,但至少拿了70分暴力

-------------------------------------分割线-----------------------------------------

这次NOIP总体来说是挂了,原本预计400结果只有270,一等是没希望了,只有吸取这次的教训,为以后的比赛积累经验。考场上要尽量保持KISS原则,结果D1T2的暴力却写的十分冗长。总的来说考场上还是应该以得分为主。另外就当是为今年的省选攒RP吧。。。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值