NOIp2016 十连测 round1

Claris大爷出的一套模拟题。问别人要到了一份题,加深了自己NOIp要滚粗的感觉。

Matser

zzDP题,我只能说我第一遍写的时候还写崩了QAQ。

//master
//by Cydiater
//2016.10.21
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <ctime>
#include <cmath>
#include <iomanip>
using namespace std;
#define ll long long
#define up(i,j,n)		for(int i=j;i<=n;i++)
#define down(i,j,n)		for(int i=j;i>=n;i--)
#define FILE "master"
#define cmax(a,b)	a=max(a,b)
#define cmin(a,b) 	a=min(a,b)
const int MAXN=305;
const int oo=0x3f3f3f3f;
inline int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
int N,K,f[MAXN][MAXN][MAXN][2];
char s1[MAXN],s2[MAXN];
namespace solution{
	void init(){
		N=read();K=read();
		scanf("%s",s1+1);
		scanf("%s",s2+1);
	}
	void DP(){
		memset(f,0,sizeof(f));
		up(i,1,N)up(j,1,N)up(k,0,K){
			f[i][j][k][0]=max(f[i][j-1][k][0],f[i-1][j][k][0]);
			if(k>0)cmax(f[i][j][k][1],f[i-1][j-1][k-1][1]+1);
			if(s1[i]==s2[j]){
				cmax(f[i][j][k][1],f[i-1][j-1][k][1]+1);
			}
			cmax(f[i][j][k][0],f[i][j][k][1]);
		}
	}
	void output(){
		cout<<f[N][N][K][0]<<endl;
	}
}
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	using namespace solution;
	init();
	DP();
	output();
	return 0;
}

Tour

通过这道题学到了bitset的简单用法,很实用。

那道题的时候想了想搞到了70分的做法,卡在了如何$O(1)$求三元环的算法上,事实证明不一定要$O(1)$,用bitset小优化一下就行了。

这道题充分说明了降维思想的重要性。

//tour
//by Cydiater
//2016.10.21
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <ctime>
#include <cmath>
#include <iomanip>
#include <cstdlib>
#include <bitset>
#include <cstdio>
using namespace std;
#define ll long long
#define up(i,j,n)		for(int i=j;i<=n;i++)
#define down(i,j,n)		for(int i=j;i>=n;i--)
#define FILE "tour"
#define LENGTH 1500
#define bs bitset<LENGTH>
const int MAXN=1505;
const int oo=0x3f3f3f3f;
inline int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
int N,LEN,cnt[MAXN];
bool mat[MAXN][MAXN];
char s[MAXN];
ll ans=0;
struct BITSET{
	bs v;
}Match[MAXN];
namespace solution{
	inline int lowbit(int i){return i&(-i);}
	void init(){
		N=read();LEN=(N-1)/LENGTH+1;
		memset(cnt,0,sizeof(cnt));
		up(i,1,N){
			scanf("%s",s+1);
			up(j,1,N)if((mat[i][j]=s[j]-‘0‘)==1)cnt[i]++;
			int now=1;
			up(j,1,LEN){
				bs S(0),tmp;
				up(k,now,min(N,now+LENGTH-1))
					if(mat[i][k])
						Match[i].v[k-now]=1;;
				now+=LENGTH;
			}
		}
	}
	int get(int x,int y){
		return (Match[x].v&Match[y].v).count();
	}
	void slove(){
		up(i,1,N)up(j,i+1,N)if(i!=j&&mat[i][j]){
			ans+=(ll)(cnt[i]-1)*(ll)(cnt[j]-1)*2LL;
			ans-=get(i,j)*2LL;
		}
	}
	void output(){
		cout<<ans<<endl;
	}
}
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	using namespace solution;
	init();
	slove();
	output();
	//cout<<"Time has passed:"<<1.0*clock()/1000<<"s!"<<endl;
	return 0;
}

Walk

做的时候最没有头绪的一道题。需要在原图上加点建立一个新图,新建的分别代表$[0,2^{20}-1]$上的每一个点,然后每个点向其二进制下有且只要以为不为1的连边,然后对于原图上的每个点,指向对应的新点一条边权为1的边,然后反向连一条边权为0的边。然后大力BFS,需要注意的是每次应该把所有与其距离为0的都加入队列中。

//walk
//by Cydiater
//2016.10.23
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <bitset>
#include <iomanip>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
using namespace std;
#define ll long long
#define up(i,j,n)		for(int i=j;i<=n;i++)
#define down(i,j,n)		for(int i=j;i>=n;i--)
#define FILE "walk"
const int MAXN=2e6+5;
const int oo=0x3f3f3f3f;
inline int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
int N,M,V[1300000],LINK[1300000],len=0,head,tail,q[1300000],dis[1300000];
bool vis[1300000];
struct edge{
	int y,next,v;
}e[MAXN*10];
namespace solution{
	inline void insert(int x,int y,int v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;}
	void init(){
		N=read();M=read();
		up(i,1,N)V[i]=read();
		up(i,1,M){
			int x=read(),y=read();
			insert(x,y,1);
		}
		up(i,0,(1<<20)-1){
			up(j,0,19)if(((1<<j)&(i))==(1<<j)){
				int x=i,y=i^(1<<j);
				insert(N+1+x,N+1+y,0);
			}
		}
		up(i,1,N){
			insert(i,N+1+V[i],1);
			insert(N+1+V[i],i,0);
		}
	}
	void ADD(int node){
		q[++tail]=node;vis[node]=1;
		for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]&&!e[i].v){
			dis[e[i].y]=dis[node];
			ADD(e[i].y);
		}
	}
	void slove(){
		memset(vis,0,sizeof(vis));
		memset(dis,0,sizeof(dis));
		head=1;tail=0;q[++tail]=1;
		dis[1]=0;vis[1]=1;
		for(;head<=tail;head++){
			int node=q[head];
			for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]){
				dis[e[i].y]=dis[node]+e[i].v;
				ADD(e[i].y);
			}
		}
		up(i,2,N)if(dis[i]==0)dis[i]=-1;
	}
	void output(){
		up(i,1,N)printf("%d\n",dis[i]);
	}
}
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	using namespace solution;
	init();
	slove();
	output();
	return 0;
}
时间: 2024-08-06 15:59:34

NOIp2016 十连测 round1的相关文章

noip2016十连测题解

以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <string> #include <bitset> #include <vector> #include <

noip2016十连测 Round #3

A:平均数 题目描述:有一天,小A得到了一个长度为n的序列.他把这个序列的所有连续子序列都列了出来,并对每一个子序列都求了其平均值,然后他把这些平均值写在纸上,并对它们进行排序,最后他报出了第k小的平均值.你要做的就是模仿他的过程. 思路:二分答案,然后判断二分的结果是不是恰好为第k位.首先统计出每一个元素和平均值的差值,记为d[i],对于区间[l,r], 如果d[l]~d[r]之和要大于0,那么这段区间的平均值就一定要大于二分的答案.于是考虑求出前缀和,记为sumd[i],那么 区间[l,r]

noip十连测round1

A:String Master 题目:所谓最长公共子串,比如串 A:“abcde”,串 B:“jcdkl”,则它们的最长公共子串为串 “cd”,即长 度最长的字符串,且在两个串中都作为连续子串出现过.给定两个长度都为 n 的字符串,对于字符串大师的你来说,求它们的最长公共子串再简单不过了.所以现在你有 k 次修改机会,每次你可以选择其中某个串的某个位置,将其修改成任意字符.你需要合理使用这 k 次修改机会,使得修改之后两个串的最长公共子串最长.相信对于字符串大师的你来说,这个问题也难不倒你. n

noip2016十连测round2

A: Divisors 题意:给定 m 个不同的正整数 a 1 ,a 2 ,...,a m ,请对 0 到 m 每一个 k 计算,在区间 [1,n] 里有多少正整数 是 a 中恰好 k 个数的约数. n,ai<=10^9,m<=200 做法:每个数的约数个数为sqrt(n)级别的,所以一共有msqrt(ai)个,对于计算答案,用哈希表判重计算即可. B:Market 题意:在比特镇一共有 n 家商店,编号依次为 1 到 n.每家商店只会卖一种物品,其中第 i 家商店的物品 单价为 c i ,价

Noi2016十连测第二场-黑暗 (二项式定理/斯特林数+CDQ+NTT)

Noi2016十连测第二场-黑暗 (二项式定理/斯特林数+CDQ+NTT) 题意: n 个点的无向图,每条边都可能存在,一个图的权值是连通块个数的 m 次方,求所有可能的图的权值和. 考虑\(dp[i][j]\)表示\(j\)个点,权值为\(i\)次方 我们首先要预处理出\(n\)个点无向联通图的数量\(g[i]\),模板题:BZOJ-3456 题解 对于\(dp[i][j]\),枚举\(1\)号点所在的连通块大小为\(x\),那么可以得到的是\(dp[i][j]=\sum dp[k][j-x]

暑假第十二测

题解:第一题: 打表找规律,从12以后每次加49,我一直在前十找规律,,找了半天,以后还是多打点,学聪明点 #include <bits/stdc++.h> #define ll long long using namespace std; int zl[4] = {1,5,10,50}; ll ans[] = {0,4,10,20,35,56,83,116,155,198,244,292,341,390,439,488,537,586,635,684,733,782,831,880,929,

NOI十连测 第五测 T1

1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 int f[257][257],n,type,V[257],g[257][257],ans,cnt; 7 char op[204]; 8 int read(){ 9 int t=0,f=1;char ch=getchar(); 10 while

[Noi2016十连测第三场]线段树

1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 using namespace std; 7 #define maxn 100005 8 #define maxk 4000005 9 int n,m,q,tot,t1,t2,ans,L[maxn][18],R[maxn][18]; 1

[NOI十连测] 二进制的世界

题意 给定一个长度为 n 的序列 A , 以及一种位运算 Op . 对于每个位置 x , 求 $\min_{y < x} A[y] ~ Op ~ A[x]$ . n <= 100000, 0 <= A[i] <= 65536 . 一个高效的Trick 我们可以贪心地尽可能使高的位大. g[x] 表示前 8 位为 x 的一个 vector . 我们维护 g 进行剪枝. 1 #include <cstdio> 2 #include <cstring> 3 #in