• 17.10.12


      • 上午
        • BZOJ 真的好难啊、、、做一个就一两个h过去了。
        • BZOJ 1019 [SHOI2008]汉诺塔

    (算了,写得太宽了,还是贴截图吧(双击看大图哦)

    image

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define ll long long
    using namespace std;
    ll f[3][105];
    int g[3][105],n;
    char to[10][3];
    int main(){
    	scanf("%d",&n);
    	for(int i=1,a,b;i<=6;i++){ 
    		scanf(" %c %c",&to[i][1],&to[i][2]);
    		a=to[i][1]-'A'+1; b=to[i][2]-'A'+1;
    		if(!g[a][1]) g[a][1]=b,f[a][1]=1;
    	}
    	for(int i=2;i<=n;i++){
    		for(int x=1,y,z;x<=3;x++){
    			y=g[x][i-1];		//x上的前i-1个应该移到y去
    			z=6-x-y;			//x上的第i个应该移到到z去 
    			f[x][i]=f[x][i-1]+1;//上面两个移动的代价 
    			if(g[y][i-1]==z)	//如果y上的i-1个应该移到z上,就直接移动 
    				f[x][i]+=f[y][i-1],g[x][i]=z;
    			else				//否则,y上的i-1个应该先移动到x上,然后z上的第i个移到y上,x上的i-1个再移到y上 
    				f[x][i]+=f[y][i-1]+1+f[x][i-1],g[x][i]=y; 
    		}
    	}
    	printf("%lld",f[1][n]);
    	return 0;
    }
    
        • 九度 1535 重叠的最长子串

    Ztraveler让我去做、、、、、、

    想了两个办法,

    一个是受bzoj 的启发,可以二分+hash做吧

    我写的另一种,是用的kmp去匹配。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define MAXN 1000005
    using namespace std;
    char t[MAXN],s[MAXN];
    int nxt[MAXN],ans; 
    int doit(char *A,char *B){
    	int la=strlen(A),lb=strlen(B);
    	nxt[0]=-1; int j=0,k=-1;
    	while(j<lb){
    		if(k==-1||B[k]==B[j]) k++,j++,nxt[j]=k;
    		else k=nxt[k];
    	}
    	j=0; int i=0;
    	while(i<la){
    		if(A[i]==B[j]||j==-1){
    			i++,j++;
    			if(i==la) return j;
    		} 
        	else j=nxt[j];
    	}
    	return 0;
    }
    int main(){
    	while(scanf("%s%s",t,s)!=EOF){
    		ans=doit(t,s);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
      • 下午
      • BZOJ 1021 [SHOI2008]Debt 循环的债务

    又是神奇dp(bzoj的dp题总是摧残我)

    首先有一个贪心的想法,对于某一种票子
    如果一开始三个人分别有A ,B ,C张
    最后通过交换变成了分别有A',B',C'张
    即变化量分别为(有正负)da ,db ,dc
    那么最少的交换次数为 (abs(da)+abs(db)+ads(dc))/2
    蛤?
    我们令pa=abs(da),pb=abs(db),pa=abs(dc),psum=pa+pb+pc
    显然一次票子的转移,会带来一个人的d变小,另一个人的d变大(再强调一次,d有正负)
    按照贪心策略,是让d>0的人把票子给d<0的人,那么两个人对应的p分别会减小1
    则psum会减小2
    这表明按照贪心策略,一次票子转移对应这psum会减小2
    所以最少的交换次数为 (abs(da)+abs(db)+ads(da+db))/2 (abs(dc)==abs(da+db))

    依次考虑每种票子的交换
    f[i][k1][k2]:表示
    前i种票子进行交换后,第一个人有k1那么多钱,第二个人有k2那么多钱时的最少交换次数
    所以枚举票子种类(确定三个人的 A ,B ,C)
        分别枚举两个个人的钱数
            分别枚举两个人有多少当前票子(得出A' ,B' ,C')
                然后用上贪心策略得出的最小转移代价,就可以刷表法转移了。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define INF 0x3f3f3f3f
    using namespace std;
    const int val[10]={0,1,5,10,20,50,100};
    int aim[5],tot[5],off[5],hav[5][10],cnt[10];
    int f[2][1005][1005],cur,sum; 
    int abs(int x){
    	return x>0?x:-x;
    }
    int main(){
    	scanf("%d%d%d",&off[1],&off[2],&off[3]);
    	for(int i=1;i<=3;i++)
    		for(int j=6;j>=1;j--){
    			scanf("%d",&hav[i][j]);
    			tot[i]+=hav[i][j]*val[j]; cnt[j]+=hav[i][j];
    		}
    	sum=tot[1]+tot[2]+tot[3];
    	aim[1]=tot[1]-off[1]+off[3];
    	aim[2]=tot[2]-off[2]+off[1];
    	if(aim[1]<0||aim[2]<0||sum-aim[1]-aim[2]<0){printf("impossible");return 0;}
    	memset(f[cur],0x3f,sizeof(f[cur]));
    	f[cur][tot[1]][tot[2]]=0;
    	for(int i=1;i<=6;i++){
    		memset(f[cur^1],0x3f,sizeof(f[cur^1]));
    		for(int k1=0;k1<=sum;k1++)
    			for(int k2=0;k1+k2<=sum;k2++){
    				if(f[cur][k1][k2]==INF) continue;
    				f[cur^1][k1][k2]=min(f[cur^1][k1][k2],f[cur][k1][k2]);
    				for(int h1=0;h1<=cnt[i];h1++)
    					for(int h2=0;h1+h2<=cnt[i];h2++){
    						int d1=h1-hav[1][i],d2=h2-hav[2][i];
    						int n1=k1+d1*val[i],n2=k2+d2*val[i];
    						if(n1<0||n2<0||sum-n1-n2<0) continue;
    						int dj=(abs(d1)+abs(d2)+abs(d1+d2))/2;
    						f[cur^1][n1][n2]=min(f[cur^1][n1][n2],f[cur][k1][k2]+dj);
    					}
    			}
    		cur^=1;
    	}
    	if(f[cur][aim[1]][aim[2]]==INF){printf("impossible");return 0;}
    	printf("%d",f[cur][aim[1]][aim[2]]);
    	return 0;
    }
      • 晚上
        • BZOJ 1022 [SHOI2008]小约翰的游戏John

    真的看不懂证明,就只有先记结论

    Anti-SG游戏定义
        1、决策集合为空的操作者胜。
        2、其余规则与SG游戏一致。

    SJ定理   
        对于任意一个Anti-SG游戏,如果定义所有子游戏的SG值为0时游戏结束,先手必胜的条件:
        1、游戏的SG值为0且所有子游戏SG值均不超过1。
        2、游戏的SG值不为0且至少一个子游戏SG值超过1。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    int SG,n,T;
    bool allin,oneout; //1
    int main(){
    	scanf("%d",&T);
    	while(T--){
    		SG=0;
    		allin=1; oneout=0;
    		scanf("%d",&n);
    		for(int i=1,x;i<=n;i++){
    			scanf("%d",&x);
    			if(x>1) allin=0,oneout=1;
    			SG^=x;
    		}
    		if((!SG&&allin)||(SG&&oneout)) printf("John
    ");
    		else printf("Brother
    ");
    	}
    	return 0;
    }
      • BZOJ
  • 相关阅读:
    console报错:No mapping found for HTTP request with URI(xxx)
    jquery,ajax详解
    spring-mvc.xml 和 application-context.xml的区别
    robot
    Linux记录history命令
    防火墙知识小结
    wireshark语法小结
    https和证书小结
    生成自签名证书:生成证书和秘钥
    查看win信任的证书办法机构(CA机构的公钥)
  • 原文地址:https://www.cnblogs.com/zj75211/p/7654916.html
Copyright © 2020-2023  润新知