2017.3.25 机房测试(数位DP,状压DP,矩阵)
来源:互联网 发布:windows平板电脑 i5 编辑:程序博客网 时间:2024/04/28 14:46
cky远在上海仍不忘为我们出题。。。
这次是DP专题。。。
天平(balance.in/balance.out)
物理老师YJ有一个长杆天平,天平的两臂长均为15,将长杆看作x轴,则平衡点在0位置处,负数位置在左臂上,正数位置在右臂上。长杆上有n个位置有挂钩可以挂秤砣。YJ有m个秤砣,质量分别为gi,每个挂钩可以不挂也可以挂任意个秤砣。YJ想要知道,在使用所有秤砣的条件下,有多少种不同的挂秤砣的方案,可以使得天平平衡?问题太过复杂,仅凭物理知识难以解决,所以请你来帮助他。
天平的平衡条件是所有秤砣的位置质量之和为0。例如有质量为2,3,4的秤砣分别挂在-3,-2,3位置处,则2(-3) + 3*(-2) + 4*3 == 0,天平是平衡的。
【输入格式】
第一行两个数n,m。表示挂钩的数目和秤砣的数目。
第二行n个不同且递增的数,第i个数表示第i个挂钩的位置,数的范围在[-15,15]内。
第三行m个不同且递增的数,第i个数表示第i个秤砣的质量,数的范围在[1,25]内。
【输出格式】
一个整数,代表能使得天平平衡的方案数。
【输入样例】
2 4
-2 3
3 4 5 8
【输出样例】
2
【样例解释】
方案1: (-2)*(3+4+5) + 3*8 = 0
方案2: (-2)(4+8) + 3(3+5) = 0
【数据规模】
10% 数据满足2≤n,m≤4。
100% 数据满足2≤n,m≤20。
【解题报告】
代码如下:
#include<cstdio>#include<cstring>#include<algorithm>#include<time.h>using namespace std;long long n,m,ans=0;long long f[25][15001]={0},c[25],r[25];int main(){ freopen("balance.in","r",stdin); freopen("balance.out","w",stdout); scanf("%I64d%I64d",&n,&m); for(int i=1;i<=n;i++) scanf("%I64d",&c[i]); for(int i=1;i<=m;i++) scanf("%I64d",&r[i]); f[0][7500]=1; for(int i=1;i<=m;i++) for(int k=1;k<=n;k++) for(int j=0;j<=15000;j++) { if(j-c[k]*r[i]<0||j-c[k]*r[i]>15000) continue; f[i][j]+=f[i-1][j-c[k]*r[i]]; } printf("%I64d",f[m][7500]); return 0;}
山峰数(hill.in/hill.out)
山峰数是指数字排列中不存在山谷(先降后升)的数,例如0,5,13,12321都是山峰数,101,1110000111都不是山峰数。
现给出n个数,请依次判断它们是否为山峰数,如果不是,输出-1。如果是,求出比它小的数中有多少个山峰数。
【输入格式】
第一行一个数n,表示询问数目。
接下来n行,每一行¬¬¬一个数x,表示询问的数。
【输出格式】
输出有n行,x如果不是山峰数,输出-1。x如果是山峰数,则输出有多少个比它小的山峰数。
【输入样例】
5
10
55
101
1000
1234321
【输出样例】
10
55
-1
715
94708
【数据规模】
20% 数据满足x ≤ 106。
100% 数据满足n ≤ 10, x ≤ 1060
【解题报告】
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;long long f[75][10][2][2];int len,a[75];char str[105];long long dfs(int p,int nu,int isdown,int lim) { if(p==len+1)return 1; if(f[p][nu][isdown][lim]!=-1)return f[p][nu][isdown][lim]; long long tmpans=0; int r=lim?a[p]:9; for(int i=0;i<=r;i++) { if(!isdown) { if(i>=nu) tmpans+=dfs(p+1,i,0,lim && i==r); else tmpans+=dfs(p+1,i,1,lim && i==r); } else if (i<=nu) tmpans+=dfs(p+1,i,1,lim && i==r); } return f[p][nu][isdown][lim]=tmpans;}int main(){ freopen("hill.in","r",stdin); freopen("hill.out","w",stdout); int tc; scanf("%d\n",&tc); while(tc--) { scanf("%s",str); len=strlen(str); for(int i=0;i<len;i++) a[i+1]=str[i]-'0'; bool isdown=false; bool ishill=true; for(int i=2;i<=len;i++) { if(a[i]<a[i-1]) isdown=true; if(isdown && a[i]>a[i-1]) { printf("-1"); ishill=false; break; } } if(ishill) { memset(f,-1,sizeof(f)); printf("%I64d",dfs(1,0,0,1)-1); } if(tc!=0) printf("\n"); } return 0;}
粉刷匠2(draw.in/draw.out)
有一个4*N的木板需要粉刷,第i行j列的颜色记为A(i, j)。
有256种颜色,记为0..255,为了使得粉刷比较好看,粉刷需要满足如下要求:
1. A(x,y) >= A(x,y-1)
2. 有一些指定的(x1, y1)和(x2, y2),要求A(x1, y1) = A(x2, y2)
请问有多少种满足要求的粉刷方式?输出答案的最后5位即可。
【输入格式】
第一行两个数n, m,表示木板的长度,和指定规则的条目个数。
接下来m行,每行四个数x1,y1,x2,y1,此规则表示A(x1, y1) 需要等于 A(x2, y2)
【输出格式】
一个整数,表示答案的末5位。
【输入样例1】
1 0
1 3
【输出样例1】
67296
【输入样例2】
1 3
1 1 2 1
1 1 3 1
4 1 3 1
【输出样例2】
00256
【提示】
输出可以使用%05d输出。
【数据规模】
30% 数据满足 n ≤ 3,m = 0
100% 数据满足1 ≤ n ≤ 15,0 ≤ M ≤ 100,X1,X2≤4,Y1,Y2≤n
【解题报告】
代码如下:
#include<cstdio>#include<cstring>#define fi first #define se second#define ll long long#define ms(x,y) memset(x,y,sizeof(x))using namespace std;int f[16][16][16][16];bool vis[16][16][16][16];int r1x[105],r2x[105],r1y[105],r2y[105];int main(){ freopen("draw.in","r",stdin); freopen("draw.out","w",stdout); int n,m,tc; int c[4]; tc=1; for(int tt=1;tt<=tc;tt++) { ms(vis,0); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d%d",&r1x[i],&r1y[i],&r2x[i],&r2y[i]); r1x[i]--;r2x[i]--; } for(int i=1;i<=m;i++){ for(c[0]=0;c[0]<=n;c[0]++) for(c[1]=0;c[1]<=n;c[1]++) for(c[2]=0;c[2]<=n;c[2]++) for(c[3]=0;c[3]<=n;c[3]++){ if(c[r1x[i]]>=r1y[i] ^ c[r2x[i]]>=r2y[i]) vis[c[0]][c[1]][c[2]][c[3]]=1; } } ms(f,0); f[0][0][0][0]=1; for(int color=0;color<=255;color++){ for(int col=0;col<=3;col++) for(c[0]=0;c[0]<=n;c[0]++) for(c[1]=0;c[1]<=n;c[1]++) for(c[2]=0;c[2]<=n;c[2]++) for(c[3]=0;c[3]<=n;c[3]++) if(c[col]<n){ int tmp=f[c[0]][c[1]][c[2]][c[3]]; c[col]++; f[c[0]][c[1]][c[2]][c[3]] = (f[c[0]][c[1]][c[2]][c[3]] + tmp) % 100000; c[col]--; } for(c[0]=0;c[0]<=n;c[0]++) for(c[1]=0;c[1]<=n;c[1]++) for(c[2]=0;c[2]<=n;c[2]++) for(c[3]=0;c[3]<=n;c[3]++) if(vis[c[0]][c[1]][c[2]][c[3]]) f[c[0]][c[1]][c[2]][c[3]]=0; } printf("%05d\n",f[n][n][n][n]); } return 0;}
棋盘(knight.in/knight.out)
有一个N*M的棋盘,要在上面摆上knight,每个格子可以放至多一个knight。
knight的攻击范围如下图:
所有knight不能互相攻击,请问总共有多少可行的摆法?答案对1000000007取模。
【输入格式】
第一行个数t,表示测试的组数。
接下来t组,每组两个整数,n和m。
【输出格式】
一共t行,第i行表示第i组的答案。
【输入样例】
4
1 2
2 2
3 2
3 31415926
【输出样例】
4
16
36
933912086
【数据规模】
70% 数据满足m≤100。
100% 数据满足t≤10, n≤3, m≤109。
代码如下:
#include<cstdio>#include<cstring>#include<iostream>#define ms(x,y) memset(x,y,sizeof(x))#define ll long longusing namespace std;const ll mod=(1e9)+7;int n,m;int fi[8]={-2,-1,1,2,2,1,-1,-2};int fj[8]={1,2,2,1,-1,-2,-2,-1};int lim;typedef ll arr[1<<8][1<<8];arr A,B,s,tmparr;int p[3][4];arr storea[5];arr stores[5];bool isstore[4];bool check(int state) { ms(p,0); int tmp=state; for(int i=1;i>=0;i--) for(int j=m-1;j>=0;j--,tmp>>=1) p[i][j]=tmp&1; for(int i=0;i<2;i++) for(int j=0;j<m;j++) if(p[i][j]) for(int d=0;d<8;d++) { int ti=i+fi[d],tj=j+fj[d]; if(ti>=0 && tj>=0 && ti<=2 && tj<m){ if(ti<2 && p[ti][tj]) return false; if(ti==2) p[ti][tj]=1; } } int line3=0; for(int j=0;j<m;j++) line3=(line3<<1)+p[2][j]; int limm=(1<<m)-1; line3=(~line3)&limm; for(int i=0;i<=limm;i++) if((i|line3)==line3) A[state][i+((state&limm)<<m)]=1; return true;}void Multi(arr A,arr B,arr C) { ms(tmparr,0); for(int i=0;i<=lim;i++) for(int j=0;j<=lim;j++) for(int k=0;k<=lim;k++) tmparr[i][j]=(tmparr[i][j]+A[i][k]*B[k][j])%mod; for(int i=0;i<=lim;i++) for(int j=0;j<=lim;j++) C[i][j]=tmparr[i][j];}int main(){ freopen("knight.in","r",stdin); freopen("knight.out","w",stdout); int tc; ms(isstore,0); scanf("%d\n",&tc); while(tc--){ scanf("%d%d",&m,&n); if(n==1){ printf("%d\n",1<<m); continue; } ms(A,0);ms(s,0);ms(B,0); n-=2; lim=(1<<2*m)-1; if(!isstore[m]) { for(int i=0;i<=lim;i++) { if(check(i))s[0][i]=1; else s[0][i]=0; } for(int i=0;i<=lim;i++) for(int j=0;j<=lim;j++) { stores[m][i][j]=s[i][j]; storea[m][i][j]=A[i][j]; } isstore[m]=true; } else{ for(int i=0;i<=lim;i++) for(int j=0;j<=lim;j++) { s[i][j]=stores[m][i][j]; A[i][j]=storea[m][i][j]; } } for(int i=0;i<=lim;i++) B[i][i]=1; while(n) { if(n&1)Multi(B,A,B); Multi(A,A,A); n>>=1; } Multi(s,B,s); ll ans=0; for(int i=0;i<=lim;i++) ans=(ans+s[0][i])%mod; cout<<ans<<endl; } return 0;}
- 2017.3.25 机房测试(数位DP,状压DP,矩阵)
- 机房模拟赛 ccount Lucas+数位dp
- BZOJ3329 Xorequ(数位dp+矩阵快速幂)
- hdu3652(数位DP)
- hdu3709(数位dp)
- codeforces55D(数位DP)
- hdu4734(数位DP)
- ural1057(数位dp)
- lightoj1205(数位DP)
- hdu4352(数位DP)
- hdu4507(数位DP)
- hdu4734(数位DP)
- poj2282(数位dp)
- hdu3652(数位dp)
- hdu_3555_Bomb(数位DP)
- hdu4734(数位DP)
- hdu2089(数位dp)
- 数位dp(hdu2089)
- about position and z-index
- 抢答器
- Ubuntu 移动工具栏位置命令
- hadoopAPI之LineReader类
- 偶数求和
- 2017.3.25 机房测试(数位DP,状压DP,矩阵)
- redis命令解析之hash类型
- jquery ajax 前后端通信传值(select 级联
- 【密码学】RC4加解密原理及其Java和C实现算法
- 求关于n的阶乘结果后面有几个零?如2016的阶乘(网易的笔试选择题)
- laravel 引入文件资源
- Java基础之加解密(一) base64编码使用
- 线程使用教程 三 IntentService
- 【学习总结】循环链表模拟约瑟夫问题和循环链表的初始化、建立、删除(按值与按位置)