There is a strange game played on a special machine. The game has m prizes labeled from 0 to m-1. First, you are given n tickets, on which there is a number ai. For each time, you can put one ticket into the machine. By pressing the button on the machine you will get a number. You can press the button as many times as you like, but at least once. If you press k times, the number from the machine will be aik mod m, namely bi, and then you can take away the prize labeled bi as your trophy. Note that one ticket can only be used once, and same bi refers to same prize, which you can only take once.
Given n, m and ai, you need to find the maximum number of different prizes you can get.
Input
The input contains no more than 30 cases. Each case has 2 lines. The first is two integers n, m (0 ≤ n ≤ 200, 0 < m ≤ 109). The second line contains n integers a0, a1, ..., an-1 (0 ≤ ai ≤ 109).
Proceed to the end of file.
Output
For each case output a integer, indicating the maximum number of different prizes you can get.
Sample Input
2 2 1 2
Sample Output
2Author: LI, Cheng
Source: ZOJ Monthly, November 2009
这道题还是比较好的。很容易看出最大匹配的模型,但是如果把a[i]^k全部生成的话,右边的点数会太大,即使取模有循环节。如此,需要利用一个结论。如果一个a[i]的k次方,可以生成大于n种不同的数,这个时候就不用再继续生成了,因为n个匹配的点已经足够保证在不干扰其他点匹配的情况下,找到一种匹配方式。
#include<cstdio> #include<map> #include<queue> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<list> #include<set> #include<cmath> using namespace std; const int maxn = 1e5 + 5; const int INF = 1e9; const double eps = 1e-6; typedef unsigned long long ULL; typedef long long LL; typedef pair<int, int> P; #define fi first #define se second struct Edge { int from, to, cap, flow; }; struct Dinic { int n, m, s, t; vector<Edge> edges; // 边数的两倍 vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号 bool vis[maxn]; // BFS使用 int d[maxn]; // 从起点到i的距离 int cur[maxn]; // 当前弧指针 void ClearAll(int n) { for(int i = 0; i < n; i++) G[i].clear(); edges.clear(); } void ClearFlow() { for(int i = 0; i < edges.size(); i++) edges[i].flow = 0; } void AddEdge(int from, int to, int cap) { //cout << from << ' ' << to << ' ' << cap << endl; edges.push_back((Edge){from, to, cap, 0}); edges.push_back((Edge){to, from, 0, 0}); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS() { memset(vis, 0, sizeof(vis)); queue<int> Q; Q.push(s); vis[s] = 1; d[s] = 0; while(!Q.empty()) { int x = Q.front(); Q.pop(); for(int i = 0; i < G[x].size(); i++) { Edge& e = edges[G[x][i]]; if(!vis[e.to] && e.cap > e.flow) { vis[e.to] = 1; d[e.to] = d[x] + 1; Q.push(e.to); } } } return vis[t]; } int DFS(int x, int a) { if(x == t || a == 0) return a; int flow = 0, f; for(int& i = cur[x]; i < G[x].size(); i++) { Edge& e = edges[G[x][i]]; if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) { e.flow += f; edges[G[x][i]^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow(int s, int t) { this->s = s; this->t = t; int flow = 0; while(BFS()) { memset(cur, 0, sizeof(cur)); flow += DFS(s, INF); } return flow; } }; Dinic g; int a[maxn]; map<LL, int> M; int main(){ int n, m; while(scanf("%d%d", &n, &m) != EOF){ for(int i = 1;i <= n;i++){ cin >> a[i]; a[i] %= m; } int source = 0, sink = n*n+1; g.ClearAll(n*n+5); for(int i = 1;i <= n;i++) g.AddEdge(source, i, 1); M.clear(); int cnt = n+1; for(int i = 1;i <= n;i++){ LL now = a[i]; map<LL, int> vis; vis.clear(); int num = 0; while(1){ vis[now] = 1; if(M.count(now)==0){ g.AddEdge(cnt, sink, 1); M[now] = cnt++; } g.AddEdge(i, M[now], 1); now = (now*a[i])%m; num++; if(num > n || vis.count(now)) break; } } cout << g.Maxflow(source, sink) << endl; } return 0; }