總結——關於2017 11 3測試的分析總結

NOIP 2017 模拟



11 3



T1:



题目:





难以置信这竟然会是T1。天呐,我到底参加的是NOI in Provinces还是NOI Plus 啊啊啊。。


——正解思路:





——我的乱搞:

暴力匹配,n * n * m大暴力。。。



——tips:

编程不止眼前的暴力,还有远方的暴力。

写暴力之前心中一定要有B数。。。




满载悲伤的代码:

(诶我操,正解代码怎么T了?????)

(代码掺了(#pragma)(GCC)(optimize("O3)),一秒能当两秒花)

#pragma GCC optimize("O3")
#include<algorithm>
#include<map>
#include<fstream>
using namespace std;
inline int read(){
	int i=0;
	char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar());
	for(;isdigit(ch);ch=getchar()) i=(i<<3)+(i<<1)+(ch^48);
	return i;
}
int buf[1024];
inline void write(int x){
	char num = 0, c[10];
	do c[++num] = x % 10 | 48, x /= 10; while (x);
	while (num) putchar(c[num--]);
	putchar('\n');
}
int tot,nxt[8001],first[8001],goal[8001];
map<int,int>id;
int f1[8001],f2[8001],f[8001],sze[8001<<1],vis[8001<<1],lef,cnt,cnt1,cnt2,cnt3;
int ans[1000][1000],spi[8001];
int tota,pos1,pos2,x,y,now;
int n,q,a[8001];
void addedge(int a,int b){nxt[++tot]=first[a];first[a]=tot;goal[tot]=b;}
int main(){
	n=read();
	q=read();
	for(register int i=1;i<=n;++i){
		a[i]=read();
		if(!id[a[i]]) id[a[i]]=++cnt;
		a[i]=id[a[i]];
	}
	for(register int i=n;i;--i) addedge(a[i],i);
	for(register int i=1;i<=cnt;++i)
		for(register int j=i+1;j<=cnt;++j){
			++tota;
			cnt1=0;cnt2=0;cnt3=0;
			for(register int p=first[i];p;p=nxt[p]) f1[++cnt1]=goal[p];
			for(register int p=first[j];p;p=nxt[p]) f2[++cnt2]=goal[p];
			cnt3=cnt1+cnt2;
			pos1=1;
			pos2=1;
			for(register int k=1;k<=cnt3;++k)
				if(pos2>cnt2||(pos1<=cnt1&&f1[pos1]<f2[pos2])) f[k]=f1[pos1++];
				else f[k]=f2[pos2++];
			now=8000;
			vis[now]=tota;
			sze[now]=f[1];
			ans[i][j]=f[1]*(f[1]-1)>>1;
			f[cnt3+1]=n+1;
			for(int k=1;k<=cnt3;++k){
				if(a[f[k]]==i) ++now;
				else --now;
				if(vis[now]<tota){
					sze[now]=0;
					vis[now]=tota;
				}
				ans[i][j]+=(f[k+1]-f[k])*sze[now]+(f[k+1]-f[k])*(f[k+1]-f[k]-1)/2;
				sze[now]+=f[k+1]-f[k];
			}
			ans[j][i]=ans[i][j];
		}
	for(register int i=1;i<=cnt;++i){
		spi[i]=0;
		lef=0;
		for(register int p=first[i];p;p=nxt[p]){
			spi[i]+=(goal[p]-lef)*(goal[p]-lef-1)>>1;
			lef=goal[p];
		}
		spi[i]+=(n-lef)*(n-lef+1)>>1;
	}
	for(register int i=1;i<=q;++i){
		x=read();
		y=read();
		x=id[x];
		y=id[y];
		if((!x&&!y)||(x==y)) write((n+1)*n/2);
		else if(!x||!y) write(spi[x^y]);
		else write(ans[x][y]);
	}
	return 0;
}





T2:


题目:






——正解思路:




——我的乱搞:

天呐,这不是个 vector + erase 风骚走位水题嚒??关键是还真TM AK了???!!!

写线段树的大佬们一脸蒙逼。。。。。。。。。。





——tips :

那么这就很监介了,,真 - 暴力出奇迹。



#pragma GCC optimize("O3")

#include <fstream>
#include <vector>

int n;
int p[100010];
std::vector <int> v;

inline void read (int &x) {
	x = 0;
	register char c = getchar();
	while (!isdigit(c)) c = getchar();
	while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
}

inline void write (int x) {
	short num = 0;
	char c[10];
	while (x) c[++num] = x % 10 | 48, x /= 10;
	while (num) putchar(c[num--]);
	putchar(' ');
}

int main () {
	read (n);
	for (register int i = 1; i <= n; ++i) read (p[i]), v.push_back(i);
	std::vector <int> :: iterator it;
	for (register int i = n; i >= 1; --i) {
		it = v.begin() + i - p[i] - 1 + p[i - 1];
		p[i] = *it;
		v.erase(it);
	}
	for (register int i = 1; i <= n; ++i) write (p[i]);
	return 0;
}

正解:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;

int n,pre,now,tmp,l,r,mid;
int a[100010],tree[100010];

void read(int &x)
{
	x=0;
	char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch))
	{
		x=(x<<3)+(x<<1)+ch-'0';
		ch=getchar();
	}
}

int lowbit(int x)
{
	return x&(-x);
}

int get(int x)
{
	int ans=0;
	while(x>=1)
	{
		ans+=tree[x];
		x-=lowbit(x);
	}
	return ans;
}

void add(int x,int y)
{
	while(x<=n)
	{
		tree[x]+=y;
		x+=lowbit(x);
	}
}

int main()
{
	//freopen("premu.in","r",stdin);
	
	read(n);
	pre=0;
	for(int i=1;i<=n;++i)
	{
		read(now);
		a[i]=now-pre;
		pre=now;
	}
	for(int i=1;i<=n;++i) add(i,1);
	for(int i=n;i>=1;i--)
	{
		tmp=i-a[i];
		l=0,r=n;
		while(l+1<r)
		{
			mid=(l+r)>>1;
			if(get(mid)<tmp) l=mid;
			else r=mid;
		}
		a[i]=r;
		add(r,-1);
	}
	for(int i=1;i<=n;++i) cout<<a[i]<<" ";
	return 0;
}




T3 :



题目:


点击回复你也查看不了


在USACO上学的暴力技巧派上用场了耶。。。。。


——正解思路:





——我的乱搞:

暴搜 + vector 剪枝。



——tips:


good good 暴力, day day 爆零。







满载一种难以言表的思想感情的代码:


#include <iostream>
#include <fstream>
#include <algorithm>

#define MIN(a, b) a = min(a, b)
#define SOLVE(a, b) \
for (register int x = 1; x <= n; ++x) for (register int y = 1; y <= n; ++y) a[i][x][y] = a[i + b][x][y] + road[i].r;\
for (register int x = 1; x <= n; ++x) {\
if (a[i + b][x][road[i].y] < inf) MIN(a[i][x][road[i].x], a[i + b][x][road[i].y] + road[i].c);\
if (a[i + b][x][road[i].x] < inf) MIN(a[i][x][road[i].y], a[i + b][x][road[i].x] + road[i].c);}

using namespace std;

struct node{
	int x, y, c, r;
}road[30001];

struct query{
	int x, y, l, r, id;
}qry[300001], tag[300001];

int n, m, q;
int ans[300001];
int Left[30001][31][31], Right[30001][31][31];

const int inf = 1e+9;

inline int read () {
	register int x = 0;
	register char c = getchar();
	while (!isdigit(c)) c = getchar();
	while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
	return x;
}

inline void write (int x) {
	char num = 0, c[10];
	if (x < 0) putchar('-'), x = -x;
	do c[++num] = x % 10 | 48, x /= 10; while (x);
	while (num) putchar(c[num--]);
	putchar('\n');
}

inline void solve(int lr, int rr, int lq, int rq) {
	if (lq > rq) return;
	if (lr == rr) {
		for (register int i = lq; i <= rq; ++i)
			if (qry[i].x != qry[i].y) {
				ans[qry[i].id] = (qry[i].x == road[lr].x and qry[i].y == road[lr].y) ? road[lr].c : -1;
			} else {
				ans[qry[i].id] = inf;
				(qry[i].x == road[lr].x and qry[i].y == road[lr].y) ? ans[qry[i].id] = road[lr].c : 0;
				MIN(ans[qry[i].id], road[lr].r);
			}
		return;
	}
	int mid = lr + rr >> 1;
	for (register int i = 1; i <= n; ++i)
		for (register int j = 1; j <= n; ++j)
			Left[mid + 1][i][j] = Right[mid][i][j] = inf;
	for (register int i = 1; i <= n; ++i)
		Left[mid + 1][i][i] = Right[mid][i][i] = 0;
	for (register int i = mid; i >= lr; --i) {SOLVE(Left, 1)}
	for (register int i = mid + 1; i <= rr; ++i) {SOLVE(Right, -1)}
	for (register int i = lq; i <= rq; ++i) if (qry[i].l <= mid and qry[i].r > mid) {
		int value = inf;
		for (register int x = 1; x <= n; ++x) MIN(value, Left[qry[i].l][x][qry[i].x] + Right[qry[i].r][x][qry[i].y]);
		ans[qry[i].id] = value < inf ? value : -1;
	}
	for (register int i = lq; i <= rq; ++i) tag[i] = qry[i];
	int wl = lq - 1, wr = rq + 1;
	for (register int i = lq; i <= rq; ++i) {
		if (tag[i].r <= mid) qry[++wl] = tag[i];
		if (tag[i].l >  mid) qry[--wr] = tag[i];
	}
	solve(lr, mid, lq, wl);
	solve(mid + 1, rr, wr, rq);
}

int main () {
	n = read(), m = read(), q = read();
	for (register int i = 1; i <= m; ++i) road[i] = (node){read(), read(), read(), read()};
	for (register int i = 1; i <= q; ++i) qry[i] = (query){read(), read(), read(), read(), i};
	solve(1, m, 1, q);
	for (register int i = 1; i <= q; ++i) write(ans[i]);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值