题意: 有n种小工具要加工,每种工具的加工时间为3到9天,给了m条加工记录。
每条记录 X $s_1$ $s_2$ 分别代表 这个工人在$s_1$到$s_2$(前闭后闭)的时间里加工了X件小工具
下一行给出这X件小工具的种类
要求的是每件工具的加工时间 (唯一解:输出各个时间;无解:Inconsistent data.;多个解:Multiple solutions.)
可以列出同余方程组:$\sum\limits_{i=0}^{n-1} a_i×x_i\equiv T \pmod{7}$
($a_i$是此人加工第i件物品的个数,$x_i$是第i件物品加工所需的时间,T是此人干活的时间)
这样列出m个同余方程 组成方程组 用高斯消元
比如第一个案例:
2 3 2 MON THU 1 2 3 MON FRI 1 1 2 3 MON SUN 1 2 2
可以列出方程组:
1×$x_0$+1×$x_1 \equiv 4 \pmod{7}$
2×$x_0$+1×$x_1 \equiv 5 \pmod{7}$
1×$x_0$+2×$x_1 \equiv 7 \pmod{7}$
\[ \left( \begin{array}{ccc}
1 & 1 & 4 \\
2 & 1 & 5 \\
1 & 2 & 7 \end{array} \right) \to \left( \begin{array}{ccc}
1 & 1 & 4 \\
1 & 0 & 1 \\
0 & 1 & 3 \end{array} \right) \to \left( \begin{array}{ccc}
1 & 0 & 1 \\
0 & 1 & 3 \\
0 & 0 & 0 \end{array} \right)\]
下面是代码:
有mod就会有要求逆元
两种求逆元的方法
1. extend gcd
注意得到的x可能为负 要x=(x%mod+mod)%mod;
1 void ex_gcd(int a, int b, int &x, int &y) 2 { 3 if(b) 4 { 5 ex_gcd(b, a%b, x, y); 6 int tmp=x; 7 x=y; 8 y=tmp-(a/b)*y; 9 } 10 else 11 { 12 x=1, y=0; 13 return ; 14 } 15 }
2.inverse element
注意 只适用于a<b 并且 ab互质
1 int inv(int a, int b) 2 { 3 return a==1? 1:inv(b%a, b)*(b-b/a)%b; 4 }
此题还有一法不求逆元:(利用欧拉函数)
即 把被除数不断加上mod 直到它能被除数整除为止
1 while(tmp%a[i][i]) 2 tmp+=mod; 3 x[i]=(tmp/a[i][i])%mod; 4 5 与以下等价 6 7 int xx, yy; 8 ex_gcd(a[i][i], mod, xx, yy); 9 xx=(xx%mod+mod)%mod; 10 x[i]=(tmp*xx)%mod; 11 12 与以下等价 13 14 x[i]=(tmp*inv(a[i][i], mod))%mod;
完整代码:
1 const int mod=7; 2 int gcd(int a, int b) 3 { 4 return b==0? a:gcd(b, a%b); 5 } 6 int lcm(int a, int b) 7 { 8 return a/gcd(a, b)*b; 9 } 10 void ex_gcd(int a, int b, int &x, int &y) 11 { 12 if(b) 13 { 14 ex_gcd(b, a%b, x, y); 15 int tmp=x; 16 x=y; 17 y=tmp-(a/b)*y; 18 } 19 else 20 { 21 x=1, y=0; 22 return ; 23 } 24 } 25 26 int a[300][300]; // 增广矩阵 27 int x[300]; // 解 28 int free_x[300]; // 标记是否为自由未知量 29 30 int Gauss(int n, int m) // n个方程 m个未知数 即 n行m+1列 31 { 32 //转换为阶梯形式 33 int col=0, k, num=0; 34 for(k=0;k<n && col<m;k++, col++) 35 {//枚举行 36 int max_r=k; 37 for(int i=k+1;i<n;i++)//找到第col列元素绝对值最大的那行与第k行交换 38 if(abs(a[i][col])>abs(a[max_r][col])) 39 max_r=i; 40 if(max_r!=k)// 与第k行交换 41 for(int j=col;j<m+1;j++) 42 swap(a[k][j], a[max_r][j]); 43 if(!a[k][col])// 说明该col列第k行以下全是0了 44 { 45 k--; 46 free_x[num++]=col; 47 continue; 48 } 49 for(int i=k+1;i<n;i++)// 枚举要删除的行 50 if(a[i][col]) 51 { 52 int LCM=lcm(abs(a[i][col]), abs(a[k][col])); 53 int ta=LCM/abs(a[i][col]); 54 int tb=LCM/abs(a[k][col]); 55 if(a[i][col]*a[k][col]<0) 56 tb=-tb; 57 for(int j=col;j<m+1;j++) 58 a[i][j]=((a[i][j]*ta-a[k][j]*tb)%mod+mod)%mod; 59 } 60 } 61 62 for(int i=k;i<n;i++) 63 if(a[i][col]) 64 return -1; // 无解 65 66 if(k<m) //m-k为自由未知量个数 67 return m-k; 68 69 // 唯一解 回代 70 for(int i=m-1;i>=0;i--) 71 { 72 int tmp=a[i][m]; 73 for(int j=i+1;j<m;j++) 74 { 75 if(a[i][j]) 76 tmp-=a[i][j]*x[j]; 77 tmp=(tmp%7+7)%7; 78 } 79 int xx, yy; 80 ex_gcd(a[i][i], mod, xx, yy); 81 xx=(xx%mod+mod)%mod; 82 x[i]=(tmp*xx)%mod; 83 } 84 return 0; 85 } 86 87 88 void init() 89 { 90 memset(a, 0, sizeof(a)); 91 memset(x, 0, sizeof(x)); 92 } 93 94 int change(char c1, char c2) 95 { 96 if(c1=='M') 97 return 1; 98 if(c1=='T' && c2=='U') 99 return 2; 100 if(c1=='W') 101 return 3; 102 if(c1=='T') 103 return 4; 104 if(c1=='F') 105 return 5; 106 if(c1=='S' && c2=='A') 107 return 6; 108 return 7; 109 } 110 111 char s1[10], s2[10]; 112 int main() 113 { 114 int n, m; 115 while(~scanf("%d%d", &n, &m)) 116 { 117 if(!n && !m) 118 break; 119 init(); 120 for(int i=0;i<m;i++) 121 { 122 int X; 123 scanf("%d%s%s", &X, s1, s2); 124 a[i][n]=((change(s2[0], s2[1])-change(s1[0], s1[1])+1)%mod+mod)%mod; 125 while(X--) 126 { 127 int t; 128 scanf("%d", &t); 129 a[i][t-1]=(a[i][t-1]+1)%mod; 130 } 131 } 132 int t=Gauss(m, n); 133 if(t==-1) 134 { 135 printf("Inconsistent data.\n"); 136 continue; 137 } 138 if(t==0) 139 { 140 for(int i=0;i<n;i++) 141 if(x[i]<=2) 142 x[i]+=7; 143 for(int i=0;i<n;i++) 144 { 145 printf("%d", x[i]); 146 if(i==n-1) 147 printf("\n"); 148 else 149 printf(" "); 150 } 151 continue; 152 } 153 printf("Multiple solutions.\n"); 154 } 155 return 0; 156 }