3.18-3.24周总结

	为迎接JSCPC选拔(反正没多大机会),而进行的周训练.

1.静下心来,能学会的还是能学会的学不会就拉倒.
2.捞钱杯杀我.明年再来
3.最菜实锤


本周学习了三部分内容,学的都很肤浅.

数位DP(只会简单题)

预处理+dp.
根据,题目要求,确定dp数组的维数,简单推到得出状态转移方程.

例题:不要62,4
题意:给定[n,m] 之前的不包含 "62"(连续),且不包含"4"的数的个数

预处理内容
首先需要一维来记录数的位数,或者说从前一位推下一位的状态.
因为与位上的数字有关,所以还需要一维来记录位上的数字.
现在我们要推出,dp [i][j],即求i位数,最高为j的合法的个数.首先,显然
dp[i][4]=0;最高位为4,合法数都为0;
这个最高位的限制条件取决于前一位是否是2,若前一位 ( i - 1 ) 最高位2,即限制前一位不能选6.否则,无论前一位取何值,都合法.

得出
j ! = 6 ,dp[ i ][ j ]=Sigma( dp[ i - 1 ][ k ]) ****;
j=6 ,dp[ i ][ j ]=Sigma( dp[ i - 1 ][ k ]) - dp[ i - 1 ][ 2 ];
j=4,dp[i][j]=0;

#include<bits/stdc++.h>
#define ll long long

using namespace std;
int T,n,m,tot,cnt=1;	char c;bool flag=0;
void rd(){
	 #ifdef Dmymax_ly
	freopen("test.in","r",stdin);
	#endif
}
ll dp[25][12];

void init(){//dp[i][j] 表示i位数字,最高位为 j 的合法数.
	memset(dp,0,sizeof(dp));
	dp[0][0]=1;
	for(int i=1;i<=10;i++){
		for(int j=0;j<=9;j++){
			if(j==4) dp[i][j]=0;
			else if(j==6){
                for(int k=0;k<=9;k++)       dp[i][j]+=dp[i-1][k];
                dp[i][j]-=dp[i-1][2];
			}
			else {
				for(int k=0;k<=9;k++){
    	           	dp[i][j]+=dp[i-1][k];
				}
			}
		}
	}
}
int dig[11];
ll solve(int x){
	cnt=0;
	memset(dig,0,sizeof(dig));
	while(x){
		dig[++cnt]=x%10;
		x/=10;
	}
	dig[cnt+1]=0;
	ll sum=0;
	for(int i=cnt;i>=1;i--){
		for(int j=0;j<dig[i];j++){
		    if (j!=4 && !(dig[i+1]==6 && j==2)){
				sum+=dp[i][j];
			}
		}
        if (dig[i]==4) break;
       if (dig[i+1]==6 && dig[i]==2) break;
	}
	return sum;
}

int main(){
	init();
	while(scanf("%d%d",&n,&m)&&(n||m)){
		printf("%lld\n",solve(m+1)-solve(n));
	}
	return 0;
}


线段树(只会模板题)

1.处理建树,与维护区间的问题 手撸不会弃了
线段树递归处理问题,根据mid与待求区间的左右关系的问题.

递归到底层,再传导到上层的方法.
2.几个基本函数

建树build函数


    void build(int l,int r,int rt){
	if(l==r){
		scanf("%d",&Tree[rt].sum);
		return;
	}
	int m=(l+r)/2;
	build(l,m,rt<<1);
	build(m+1,r,rt<<1|1);
	pushup(rt);
}

更新函数(向上)

void pushup(int rt){
	Tree[rt].sum=Tree[rt<<1].sum+Tree[rt<<1|1].sum;
	Tree[rt].maxn=max(Tree[tr>>1].maxn+Tree[tr>>1|1].maxn);
}

更新函数(向下)

void pushdown(int rt,int m) {
       if (Tree[rt].lazy) {
              Tree[rt<<1].lazy += Tree[rt].lazy;
              Tree[rt<<1|1].lazy += Tree[rt].lazy;
              Tree[rt<<1].sum += Tree[rt].lazy * (m - (m >> 1));
              Tree[rt<<1|1].sum += Tree[rt].lazy * (m >> 1);
              Tree[rt].lazy = 0;
       }
}

单点修改

void change(int l,int r,int k,int x,int rt){
	if(l==r){
		Tree[rt].sum+=x;
		return;
	}
	int m=(l+r)/2;
	if(k<=m) change(l,m,k,x,rt<<1);
	else change(m+1,r,k,x,rt<<1|1);
	pushup(rt);
}

区间查询

int query(int L,int R,int l,int r,int rt){
	if(L<=l&&R>=r){
		return Tree[rt].sum;
	}
	int res=0;
	int m=(l+r)/2;
	if(L<=m) res+=query(L,R,l,m,rt<<1);
	if(R>=m+1) res+=query(L,R,m+1,r,rt<<1|1);
	return res;
}

区间修改

void update(int L,int R,int c,int l,int r,int rt) {
       if (L <= l && r <= R) {
              Tree[rt].lazy += c;
              Tree[rt].sum += (ll)c * (r - l + 1);
              return ;
       }
       pushdown(rt , r - l + 1);
       int m = (l + r) >> 1;
       if (L <= m) update(L , R , c , l , m , rt << 1);
       if (m < R) update(L , R , c , m + 1 , r , rt << 1 | 1);
       pushup(rt);
}
	敌兵布阵
	题意:简单的单点修改,区间查询.
#include<bits/stdc++.h>
#define ll long long
#define scafn scanf
#define prinft printf
const int maxx=55500;
using namespace std;
struct p{
	int sum;
}Tree[maxx<<2];
int T,n,m,tot,cnt,x,y;	char s[5];
void pushup(int rt){
	Tree[rt].sum=Tree[rt<<1].sum+Tree[rt<<1|1].sum;
	//Tree[rt].maxn=max(Tree[tr>>1].maxn+Tree[tr>>1|1].maxn);
}
void build(int l,int r,int rt){
	if(l==r){
		scanf("%d",&Tree[rt].sum);
		return;
	}
	int m=(l+r)/2;
	build(l,m,rt<<1);
	build(m+1,r,rt<<1|1);
	pushup(rt);
}
void change(int l,int r,int k,int x,int rt){
	if(l==r){
		Tree[rt].sum+=x;
		return;
	}
	int m=(l+r)/2;
	if(k<=m) change(l,m,k,x,rt<<1);
	else change(m+1,r,k,x,rt<<1|1);
	pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
	if(L<=l&&R>=r){
		return Tree[rt].sum;
	}
	int res=0;
	int m=(l+r)/2;
	if(L<=m) res+=query(L,R,l,m,rt<<1);
	if(R>=m+1) res+=query(L,R,m+1,r,rt<<1|1);
	return res;
}
void rd(){
	 #ifdef Dmymax_ly
	freopen("test.in","r",stdin);
	#endif
}
int main(){
	rd();
	scanf("%d",&T);
	int num=T;
	while(T--){
		printf("Case %d:\n",num-T);
		scanf("%d",&n);
		build(1,n,1);
		while(scanf("%s",s)){
			if(s[0]=='E') break;
			if(s[0]=='A'){
				scanf("%d %d",&x,&y);
				change(1,n,x,y,1);
			}
			if(s[0]=='S'){
				scanf("%d %d",&x,&y);
				change(1,n,x,-y,1);
			}
			if(s[0]=='Q'){
				scanf("%d %d",&x,&y);
				printf("%d\n",query(x,y,1,n,1));
			}
		}
	}
	return 0;
}

	A simple problem 
	题意:区间修改+区间查询	
	注意点: [**cin读入会超时,应该用scanf**]
	(贴假代码怕是要被打死)
#include<stdio.h>
#include<iostream>
#define ll long long
using namespace std;
const int maxx = 211111;
int T,n,m,tot,cnt,x,y,v; char s[5];
struct p{
	ll maxn,sum;
	ll lazy;
}Tree[maxx<<2];
void pushup(int rt) {
       Tree[rt].sum = Tree[rt<<1].sum + Tree[rt<<1|1].sum;
}
void pushdown(int rt,int m) {
       if (Tree[rt].lazy) {
              Tree[rt<<1].lazy += Tree[rt].lazy;
              Tree[rt<<1|1].lazy += Tree[rt].lazy;
              Tree[rt<<1].sum += Tree[rt].lazy * (m - (m >> 1));
              Tree[rt<<1|1].sum += Tree[rt].lazy * (m >> 1);
              Tree[rt].lazy = 0;
       }
}
void build(int l,int r,int rt) {
       Tree[rt].lazy = 0;
       if (l == r) {
              scanf("%lld",&Tree[rt].sum);
              return ;
       }
       int m = (l + r) >> 1;
       build(l , m , rt << 1);
       build(m + 1 , r , rt << 1 | 1);
       pushup(rt);
}
void update(int L,int R,int c,int l,int r,int rt) {
       if (L <= l && r <= R) {
              Tree[rt].lazy += c;
              Tree[rt].sum += (ll)c * (r - l + 1);
              return ;
       }
       pushdown(rt , r - l + 1);
       int m = (l + r) >> 1;
       if (L <= m) update(L , R , c , l , m , rt << 1);
       if (m < R) update(L , R , c , m + 1 , r , rt << 1 | 1);
       pushup(rt);
}
ll query(int L,int R,int l,int r,int rt) {
       if (L <= l && r <= R) {
              return Tree[rt].sum;
       }
       pushdown(rt , r - l + 1);
       int m = (l + r) >> 1;
       ll res = 0;
       if (L <= m) res += query(L , R , l , m , rt << 1);
       if (m < R) res += query(L , R , m + 1 , r , rt << 1 | 1);
       return res;
}
void rd(){
	 #ifdef Dmymax_ly
	freopen("test.in","r",stdin);
	#endif
}
int main(){
    cin>>n>>m;
    build(1 , n , 1);
    while (m--) {
		cin>>s;
		if (s[0] == 'Q') {
			cin>>x>>y;
			cout<<query(x , y , 1 , n , 1)<<endl;
		}else{
			cin>>x>>y>>v;
			update(x , y , v , 1 , n , 1);
		}
	}return 0;
}

博弈

NP 状态的确定+大力猜结论+玄学SG

	NP状态的转换
	若该状态的所有后继状态皆为必败态,则该点必败.
	若该状态的所有后继状态存在一必胜态,则该点必胜.
	
	例题 II with GG
	题意:轮流移动棋子,往下,左,左下.最先将棋子移动到原点处胜.

给定的 n 和 m 不大,所以直接由起点推出棋盘上的每一个点的状态(先手胜为1)
对于第一行 ( 坐标系 ) 由于只能左移,简单易的列数为奇数先手败,偶数则胜;第一列,亦然.
若 vis[ i - 1 ] [ j - 1 ]== 1 || vis[ i ] [ j - 1]==1||vis[ i - 1 ][ j - 1 ] == 1,则 v i s [ i ][ j ]=1
若 vis[ i - 1 ] [ j - 1 ]== 0 || vis[ i ] [ j - 1]==0 || vis[ i - 1 ][ j - 1 ] == 0,则 v i s [ i ][ j ]=0

	大力猜结论,暴力出奇迹

写完蓝桥杯,发现自己暴力算法尽然学的都不行

	玄学SG
	SG 函数是,即mex函数,是定义在集合上的一个函数.不属于集合内的最小自然数.如,mex{ 0 ,2 , 3 , 5 }=1; mex{ 0 , 1  , 2 }=3;(0是自然数) 
	规定SG(0)=0;

这里就直接贴一下网址

[ 博弈论入口 ]https://www.cnblogs.com/Wolfycz/p/8430991.html


很显然,这周很水.

	                                                                                 2019.3.24
																			         		Dmymax_ly
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值