jsoi2015R2D2和R3D1测试总结

传送门:然而并没有...

这两天测试状态比较奇怪,前面1.5h-2h完全不知所措,一脸茫然,感觉自己吃枣药丸

后面才发现有很多题可捉的,并没有想象的那么难,但是时间已经不充裕了...


R2D2

T1:不知所措数学题

一开始总想着有什么DP可以拿一些部分分

然而连30分DP都不会....

咦,好像有大样例

那就找一发规律

妈呀真是2^(nk)

快速幂完事....


考完冷静了一下发现还是比较容易证的

首先n位每位相互独立,所以可以只考虑一位

设f[k]表示k*k的三角形的方案数

考虑f[k+1]怎么递推

如果最左下角的数是0,那么最后一行已经确定了,都会是0

而且不会对上面的k*k的三角形有影响,所以方案数是f[k]

如果是1,同理,最左边一行已经确定了,都必须是1

而且也不会对右边的k*k的三角形有影响,所以方案数是f[k]

所以f[k+1]=2*f[k]

所以一位的答案就是2^k

n位乘起来就好了,答案就是2^(nk)


T2:数据结构题?

一看到这题我就觉得是数据结构题,然而想来想去并不知道怎么维护....于是弃疗了

后来我才发现一个显然的性质

就是最大和最小一定取在端点,不然不是最优

然后我们就可以分数规划了

情况有点多

假设i是右端点,j是左端点

假设a[i]为max,a[j]为min

那么(a[i]-a[j])/(i-j+K)=ans

变形得(a[i]-i*ans)-(a[j]-j*ans)=k*ans

所以我们二分一下ans,有满足左边大于右边的,ans就可以更大

左边最大值可以用单调队列做

记A[i]=a[i]-ans*i

如果后面加进来的A[i]比队尾要小,队尾就没有意义了,可以删去

对于区间长度是[L,R]的限制,初始时保持距离为L,加入队列时从队头删去距离超过R-1的点即可

反过来类似,注意一些细节


另外就是区间长为L时

类似地,(a[i]-a[j])/(L-1+K)=ans

变形得:a[i]-a[j]=ans*(L-1+K)

也是二分,单调队列维护即可

复杂度O(nlogmaxans)


T3:字符串神题?

突然发现字符串长<=10.....

拿个可持久化trie维护一下就好了

儿子节点从父亲节点继承trie,再把边上的字符串插入进去即可

每次用ans[x]+ans[y]-2*ans[lca]即可


R3D1

T1:一开始想到了一个玄学做法,好像很复杂的样子...然后就安心打暴力去了

后来证了一下发现是对了,加个bitset好像可以卡过


我们对于每个点求出它能到哪些点,记为g[i][maxn],这个可以压位做到m*n/32

然后对于每个点v,处理哪些连向它的边可删

如果一个它的前驱x能够到它的另一个前驱y

那么显然x连向它的边可以删去了

然后证明没有其他可删的边

假设有一个边可删,且不满足上面的条件

那么说明x到v有其他路径

那么这条路经一定要经过v的另一个前驱z,那么x可以到z,不符假设

所以不存在这样的边

具体实现就对每个点求一个bitset,表示是否是x的前驱

在把它和每个前驱的g[i]and一下,如果有1,就说明可以从其他点过来,然后就可以删掉这条边

然后发现有点卡常,怕70分都没了,于是只开到1000,70保平安...

然后发现标程压64位.....


T2:神奇的插头DP


妈呀200*200....

一定有特殊的DP方法

D了半天不知所措....


突然发现这是很简单的网络流,每栋房子是一个点,源向它连卖给A的权值,它向汇连卖给B的的权值,相邻的点连建围墙的权值,求出最小割,拿总收益减去就是了...


然后就是15分钟写网络流系列...

然后就爆零被教做人了...


T3:这个真是字符串神题,看了标程好像是后缀数组,暴力还挂了,不知所措...


得分情况:100+0+100+70+0+0

有些题目就是要敢于去想,要相信能写出来

但是有时写暴力求稳也是很重要的...



R2D1

T1:

#include
#include
#include
#include
typedef long long ll;
const ll mod=(ll)1e9+7;
using namespace std;
int n,k;

ll qpow(int a,ll b){
	ll res=1,j=a;
	while (b){
		if (b&1) res=res*j%mod;
		j=j*j%mod,b>>=1;
	}
	return res;
}

int main(){
	scanf("%d%d",&n,&k);
	printf("%lld\n",qpow(2,1ll*n*k));
	return 0;
}

T2:
#include
#include
#include
#include
#include
const double eps=1e-6;
const int maxn=100010;
using namespace std;
int cas,a[maxn],n,K,L,R;
struct Tque{
	int pos[maxn],head,tail;double val[maxn];
	void clear(){head=1,tail=0;}
	void pushmin(int p,double v){
		//maximize a[i]-miu*i-a[j]+miu*j
		//if A[j]<=A[q[tail]] 
		//because j>q[tail]
		//j is better than q[tail]
		while (head<=tail&&v<=val[tail]) tail--;
		val[++tail]=v,pos[tail]=p;
	}
	void pushmax(int p,double v){
		while (head<=tail&&v>=val[tail]) tail--;
		val[++tail]=v,pos[tail]=p;
	}
	void pop1(int p){while (head<=tail&&p-pos[head]+1>R) ++head;assert(p-pos[head]+1<=R);}
	void pop2(int p){while (head<=tail&&pos[head]=p-L+1);}
	double top(){return val[head];}
}q;

bool check(double miu){
	q.clear();
	for (int i=L;i<=n;i++){
		int j=i-L+1;
		q.pushmin(j,a[j]-j*miu),q.pop1(i);
		if (a[i]-miu*i-q.top()+eps>=K*miu) return 1;
	}
	q.clear();
	for (int i=L;i<=n;i++){
		int j=i-L+1;
		q.pushmax(j,a[j]+j*miu),q.pop1(i);
		if (q.top()-a[i]-miu*i+eps>=K*miu) return 1;
	}
	q.clear();
	for (int i=1;i<=n;i++){
		q.pushmin(i,a[i]),q.pop2(i);
		if (a[i]-q.top()+eps>=(L-1+K)*miu) return 1;
	}
	q.clear();
	for (int i=1;i<=n;i++){
		q.pushmax(i,a[i]),q.pop2(i);
		if (q.top()-a[i]+eps>=(L-1+K)*miu) return 1;
	}
	return 0;
}

int main(){
	//freopen("gift.in","r",stdin);freopen("gift.out","w",stdout);
	scanf("%d",&cas);
	while (cas--){
		scanf("%d%d%d%d",&n,&K,&L,&R);
		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
		double l=0.0,r=1000.0,mid=500.0;
		while (r-l>eps){
			if (check(mid)) l=mid;
			else r=mid;
			mid=(l+r)/2;
		}
		printf("%.4lf\n",l);
	}
	return 0;
}
/*
1
5 1 2 4
1 2 3 4 5
*/

T3:

#include
#include
#include
#include
const int maxn=100010,maxm=200010,maxt=1200010;
using namespace std;
int n,Q,pre[maxm],now[maxn],son[maxm],val[maxm][15],tot,pp[15],fa[maxn][22],dep[maxn];char tmp[15];

struct Trie{
	int root[maxn],ch[maxt][28],tot,cnt[maxt];
	void insert(int now,int pre,int s[]){
		int len=0;
		while (s[len+1]) len++;
		//for (int i=1;i<=len;i++) printf("%d ",s[i]);puts("s[i]");
		for (int i=1;i<=len;i++){
			for (int j=1;j<=26;j++){
				if (j==s[i]) ch[now][j]=++tot,cnt[tot]=cnt[ch[pre][j]]+1;
				else ch[now][j]=ch[pre][j];
			}
			now=ch[now][s[i]],pre=ch[pre][s[i]];
		}
		for (int j=1;j<=26;j++) ch[now][j]=ch[pre][j];
	}
	int query(int now,int s[]){
		for (int i=1;s[i];i++) now=ch[now][s[i]];//,printf("now=%d s[i]=%d cnt=%d\n",now,s[i],cnt[now])
		//puts("\n");
		return cnt[now];
	}
}T;

void add(int a,int b){
	pre[++tot]=now[a],now[a]=tot,son[tot]=b;
	for (int i=1;pp[i];i++) val[tot][i]=pp[i];
}

void dfs(int x){
	for (int i=1;i<=19;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int y=now[x];y;y=pre[y]) if (son[y]!=fa[x][0]){
		T.root[son[y]]=++T.tot,T.insert(T.root[son[y]],T.root[x],val[y]);
		dep[son[y]]=dep[x]+1,fa[son[y]][0]=x,dfs(son[y]);
	}
}

int lca(int a,int b){
	if (dep[a]=0;i--)
		if (fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];
	return fa[a][0];
}

void change(){
	int len=strlen(tmp+1);
	memset(pp,0,sizeof(pp));
	for (int i=1;i<=len;i++) pp[i]=tmp[i]-'a'+1;
}

int main(){
	freopen("strings.in","r",stdin);freopen("strings.out","w",stdout);
	scanf("%d",&n);
	for (int i=1,x,y;i

R3D1

T1:这个程序只能过70分,但是是标算,还要特殊的卡常数技巧(标程是压64位,可能在64位机上要快一些就过了)

#include
#include
#include
#include
#include
const int maxn1=18,maxn=30010,maxm=100010;
using namespace std;
struct Edge{int x,y;}E[maxm];
bitset map[maxn];
int n,m,ans,pw[maxn1],ord[maxn];bool g[maxn1][maxn1],con[maxn1][maxn1],tmp[maxn1][maxn1],bo[maxn1];

struct Twork1{
	void dfs(int x){
		bo[x]=1;
		for (int i=1;i<=n;i++) if (g[x][i]&&!bo[i]) dfs(i);
	}
	bool check(int s){
		memset(g,0,sizeof(g)),memset(tmp,0,sizeof(tmp));
		for (int i=0;i tmp;
		int ans=0;
		for (int x=1;x<=n;x++){
			tmp.reset();
			for (int y=now[x];y;y=pre[y])
				tmp[son[y]]=1;
			for (int y=now[x];y;y=pre[y])
				if ((tmp&map[son[y]]).any()) ans++;
		}
		printf("%d\n",ans);
	}		
}T2;

int main(){
	freopen("graph.in","r",stdin);freopen("graph.out","w",stdout);
	pw[0]=1;for (int i=1;i<=16;i++) pw[i]=pw[i-1]<<1;
	scanf("%d%d",&n,&m);
	if (n<=15&&m<=15) T1.work();
	else T2.work();
	return 0;
}
/*
5 6
1 2
2 3
3 5
4 5
1 5
1 3

7 8
1 2
2 5
5 7
1 3
6 7
1 4
4 7
3 5

*/

T2:
#include
#include
#include
#include
#include
#define aabs(a) (a>0?a:-(a))
const int maxn=500010,maxm=1000010,inf=(int)1e9;
using namespace std;
int n,m,ans,pre[maxm],now[maxn],son[maxm],val[maxm],tot,dis[maxn],head,tail,q[maxm+10];
int id(int x,int y){return (x-1)*m+y;}

struct Flow{
	int S,T;
	void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
	void ins(int a,int b,int c){add(a,b,c),add(b,a,0);assert(totmaxn) head=1;
			int x=q[head];
			for (int y=now[x];y;y=pre[y])
				if (val[y]&&dis[son[y]]==-1){
					if (++tail>maxn) tail=1;
					dis[son[y]]=dis[x]+1,q[tail]=son[y];
				}
		}
		return dis[T]>0;
	}
	int find(int x,int low){
		if (x==T) return low;
		int y,res=0;
		for (y=now[x];y;y=pre[y]){
			if (dis[son[y]]!=dis[x]+1||!val[y]) continue;
			int tmp=find(son[y],min(low,val[y]));
			res+=tmp,low-=tmp,val[y]-=tmp,val[y^1]+=tmp;
			if (!low) break;
		}
		if (!y) dis[x]=-1;
		return res;
	}
	void work(){
		int res=0;
		while (bfs()) res+=find(S,inf);
		printf("%d\n",ans-res);
	}
}F;

void init(){
	scanf("%d%d",&n,&m),F.clear();
	for (int i=1;i<=n;i++)
		for (int j=1,v;j<=m;j++){
			scanf("%d",&v),ans+=aabs(v);
			if (v>=0) F.ins(F.S,id(i,j),v);
			else F.ins(id(i,j),F.T,-v);
		}
	for (int i=1;i

T3:不知所措....



转载于:https://www.cnblogs.com/thythy/p/5493643.html

你可能感兴趣的:(jsoi2015R2D2和R3D1测试总结)