【P1825】表达式整除
又自己写出来了好开心OvO
原题:
24点这个游戏好多人都玩过,就是给你4个数,添加相应的运算符,是否可以得到结果是24.
小x在玩了很多遍这个游戏之后,想把这个游戏给改变一下。
给你n个整数,在n个整数间,只能添加+和- 两种运算符。
比如:给你4个整数:17,5,-21,-15。
你可以构成下列8个表达式:
17+5+(-21)+15=16
17+5+(-21)-15=-14
17+5-(-21)+15=58
17+5-(-21)-15=28
17-5+(-21)+15=6
17-5+(-21)-15=-24
17-5-(-21)+15=48
17-5-(-21)-15=18
现在的问题是:给你n个数,能够构成一个表达式,让这个表达式的值能被某个给定的数整除。
上面的例子中:可以被7整除,但是不能被5整除。
k组数据,k<=20,1<=n<=10000, 2<=x<=100
这道题说是DP实际上算递推吧
关于乘出与取模的DP(递推),枚举取模后的数似乎是一个切入点
这题膜的数<=100,就可以直接开一个二维bool,visited(i,j)表示第i阶段能不能取到某个模j
由于计算过程中会出现负数,所以visited第二维开二倍,用m作为0点,每次枚举1到m*2再减去m即可枚举1-m到m-1
在每个阶段i中枚举上一阶段的1-m到m-1作为模数j,如果上阶段的j能取到,当前阶段的(j-m+a[i])%m+m,(j-m-a[i])%m+m就能取到
最后检查第n阶段能否取到m即可
需要注意:
计算中可能出现负数
visited第二维开双倍
因为是多组数据,所以每组数据visited都要清空
代码:
1 //3_108_120_116 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 using namespace std; 8 int read(){int z=0,mark=1; char ch=getchar(); 9 while(ch<'0'||ch>'9'){if(ch=='-')mark=-1; ch=getchar();} 10 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 11 return z*mark; 12 } 13 int n,m,a[11000]; 14 bool visited[11000][210]; 15 int main(){//freopen("ddd.in","r",stdin); 16 int T; cin>>T; 17 while(T --> 0){//趋向于 18 memset(visited,0,sizeof(visited)); 19 cin>>n>>m; 20 for(int i=1;i<=n;i++) a[i]=read()%m; 21 visited[0][m]=true; 22 for(int i=1;i<=n;i++) 23 for(int j=1;j<m*2;j++)if(visited[i-1][j]){ 24 visited[i][(j-m+a[i])%m+m]=true; 25 visited[i][(j-m-a[i])%m+m]=true; 26 } 27 cout<<((visited[n][m])?"Divisible":"Not divisible")<<endl; 28 } 29 return 0; 30 }