题目大意:
给若干个(40个)数字,每个数字有一个取值范围。
给若干个区间【l,r】和flag表示奇偶
问,让[L,R]区间的数字,的数字和为奇/偶, 的方案总数
假设s[i]为前i个数字的前缀和。 对于L,R而言,就是s[r]和s[l-1]。
如果[L,R]为奇数,那么就是s[r]-s[l-1]为奇数。
我们并不十分关心s[i]是多少,只在意是奇还是偶,并且是否可行。
f[i][0/1]表示s[i]为偶/奇。
这样如果题目给了 【L,R】的话,那么s[l-1]和s[r]的奇偶关系就是关联的。
最后题目一定给出若干个连通快,连通块内的取值,决定一个值,就决定了整个连通快。
对于所有连通快,暴力一下就行了。题解大致描述的就是这样的方法
暴力后,可以知道每个s[i]的取值是任意,还是必须奇还是必须偶。这个问题DP就行了,记录方案比较麻烦。
切记: 题目可以出现一个数字的取值范围是[5,5]或者[7,7]这样的。 所以多出一些细节。
数据十分弱,不考虑也能过(网上我搜到的所有人的程序都过不了下面这组数据……2016年8月15日19:44:56 当然我能过QAQ,对拍怎么都过不了……)
1
3 2
2 5
4 4
4 6
1 2 1
1 3 1
答案无论如何,最小字典序的第二个数字也不会是5吧~? 网上不少人程序都是错的……
因为数据弱,我也不能保证我程序就是对的。
#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
#include <tr1/unordered_map>
using namespace std::tr1;
using std::sort;
using std::max;
using std::cout;
using std::stack;
using std::cin;
using std::endl;
using std::swap;
using std::pair;
using std::vector;
using std::set;
using std::map;
using std::multiset;
using std::queue;
using std::greater;
using std::string;
using std::priority_queue;
using std::max_element;
using std::min_element;
using __gnu_pbds::pairing_heap_tag;
__gnu_pbds::priority_queue<int, greater<int>, pairing_heap_tag> heap;
#define Hash unordered_map
#define pr(x) cout<<#x<<" = "<<x<<" "
#define prln(x) cout<<#x<<" = "<<x<<endl
typedef long long LL;
LL mymin(LL a, LL b)
{
if (a>b) return b;
return a;
}
const int maxn = 50;
int n, m;
int low[maxn], up[maxn];
struct edge{int will,relationship;};
vector<edge>g[maxn];
int block_cnt;
int belong[maxn], block_idx[maxn];
int f[maxn];
const LL mod = 1e9+7;
const int INF = 0x3f3f3f3f;
void init()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++ i)
{
scanf("%d%d", &low[i], &up[i]);
}
for (int i = 0; i <= n; ++ i) g[i].clear();
for (int i = 1; i <= m; ++ i)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
--a;
g[a].push_back({b,c});
g[b].push_back({a,c});
}
memset(belong, 0, sizeof(belong));
memset(f, -1, sizeof(f));
block_cnt=0;
}
queue<int>q;
void bfs(int k)
{
if (g[k].size() == 0) return ;//孤立点
while (!q.empty())q.pop();
q.push(k);
belong[k] = ++block_cnt;
block_idx[block_cnt] = k;
while (!q.empty())
{
int now = q.front();
q.pop();
for (auto x : g[now])
{
int will = x.will;
if (belong[will]) continue;
belong[will] = block_cnt;
q.push(will);
}
}
}
bool ranse(int block, int colo) //返回false则为无法染色
{
int now = block_idx[block];
for (int i = 0; i <= n; ++ i)
if (belong[i] == block) f[i] = -1;
while (!q.empty())q.pop();
q.push(now);
f[now] = colo;
while (!q.empty())
{
int now = q.front();
q.pop();
for (auto x : g[now])
{
int will = x.will;
if (f[will] != -1 && f[will] != f[now] ^ x.relationship) return false;
if (f[will] == -1)
{
f[will] = f[now] ^ x.relationship;
q.push(will);
}
}
}
return true;
}
int output[maxn];
LL get(int x, int flag)//flag 为0或1。 第x个数字,选0偶数,1奇数个数字,的总方案数
{
if (low[x]%2 ==1 && up[x]%2==1) return (up[x] - low[x]) / 2 + flag;
if (low[x]%2 != up[x]%2) return (up[x] - low[x] + 1) / 2;
return (up[x] - low[x])/2 + (flag^1);
}
int getnum(int x, int flag)//得到x的最小 0偶数 1奇数
{
if (low[x]%2 == flag) return low[x];
//else return low[x]+1;
if (low[x] + 1 <= up[x]) return low[x] + 1;
return 0x3f3f3f3f; //表示无解
}
vector<int>gg[maxn][2];
vector<int>ww[maxn][2];
LL h[maxn][2];
LL p[maxn][2];
int ans;
int tmp_output[maxn];
int vis[maxn][2];
void find(int a, int b)
{
vis[a][b] = 1;
if (h[a][b] == 0) return;
if (a == n)
{
for (int i = 1; i <= n; ++ i)
{
if (tmp_output[i] == output[i]) continue;
if (tmp_output[i] > output[i]) return;
if (tmp_output[i] < output[i]) break;
}
for (int i = 1; i <= n; ++ i)
output[i] = tmp_output[i];
return;
}
if (gg[a][b].size() == 0) return;
if (gg[a][b].size() == 1)
{
int j = gg[a][b][0];
tmp_output[a+1] = ww[a][b][0];
if (vis[a+1][j]) return;
find(a + 1, j);
return;
}
//否则先走字典序小的
if (ww[a][b][0] > ww[a][b][1])
{
swap(ww[a][b][0], ww[a][b][1]);
swap(gg[a][b][0], gg[a][b][1]);
}
int j1 = gg[a][b][0];
int j2 = gg[a][b][1];
tmp_output[a+1] = ww[a][b][0];
if (!vis[a+1][j1]) find(a +1, j1);
tmp_output[a+1] = ww[a][b][1];
if (!vis[a+1][j2]) find(a + 1, j2);
}
void check()
{
for (int i = 0; i <=n;++i)
for (int j = 0; j <=1;++j)
{
gg[i][j].clear();
ww[i][j].clear();
}
memset(h, 0, sizeof(h));
memset(p,0x3f, sizeof(p));
h[0][0] = 1;//方案总数
for (int i = 1; i <= n; ++ i)
{
if (f[i] == -1)
{
if (h[i - 1][0]) //前一位可以是偶数
{
if (h[i - 1][0] * get(i , 0))
{
gg[i - 1][0].push_back(0);
ww[i - 1][0].push_back(getnum(i, 0));
h[i][0] += h[i - 1][0] * get(i , 0);
h[i][0] %= mod;
p[i][0] = mymin(getnum(i, 0), p[i][0]);
}
if (h[i - 1][0] * get(i, 1))
{
gg[i - 1][0].push_back(1);
h[i][1] += h[i - 1][0] * get(i, 1);
h[i][1] %= mod;
p[i][1] = mymin(getnum(i, 1), p[i][1]);
ww[i - 1][0].push_back(getnum(i, 1));
}
}
if (h[i - 1][1])
{
if (h[i - 1][1] * get(i, 1))
{
gg[i - 1][1].push_back(0);
h[i][0] += h[i - 1][1] * get(i, 1);
h[i][0] %= mod;
p[i][0] = mymin(getnum(i, 1), p[i][0]);
ww[i - 1][1].push_back(getnum(i, 1));
}
if (h[i - 1][1] * get(i, 0))
{
gg[i - 1][1].push_back(1);
h[i][1] += h[i - 1][1] * get(i, 0);
h[i][1] %= mod;
p[i][1] = mymin(getnum(i, 0), p[i][1]);
ww[i - 1][1].push_back(getnum(i, 0));
}
}
}
else
{
int v=f[i];
if (h[i - 1][0] * get(i, v ^ 0))
{
gg[i - 1][0].push_back(v);
h[i][v] += h[i - 1][0] * get(i, v ^ 0);
h[i][v] %= mod;
p[i][v] = mymin(getnum(i, v ^ 0), p[i][v]);
ww[i - 1][0].push_back(getnum(i, v^0));
}
if (h[i - 1][1] * get(i, v ^ 1))
{
gg[i - 1][1].push_back(v);
h[i][v] += h[i - 1][1] * get(i, v ^ 1);
h[i][v] %= mod;
p[i][v] = mymin(getnum(i, v ^ 1), p[i][v]);
ww[i - 1][1].push_back(getnum(i, v^1));
}
}
if (!h[i][0] && !h[i][1])
{
//无解
return;
}
}
memset(vis, 0, sizeof(vis));
find(0, 0);
ans = (ans + h[n][0] + h[n][1]) % mod;
}
void dfs(int deep)
{
if (deep > block_cnt)
{
check();
return;
}
if (ranse(deep, 0)) dfs(deep + 1);
if (ranse(deep, 1)) dfs(deep + 1);
}
void doit()
{
ans = 0;
for (int i = 0; i <= n; ++ i)
if (!belong[i]) bfs(i);
memset(output, 0x3f, sizeof(output));
memset(f, -1, sizeof(f));
if (belong[0] == 1)
{
//cout<<"!"<<endl;
if (ranse(1, 0)) dfs(2);
//否则显然无解啊
}else
{
dfs(1);
}
printf("%lld\n", ans);
if (ans == 0)
{
printf("-1\n");
return;
}
for (int i = 1; i < n; ++ i) printf("%d ", output[i]);
printf("%d\n", output[n]);
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
init();
doit();
}
return 0;
}
数据生成器:
#include <cstdio>
#include <stack>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <ctime>
#include <queue>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
#define pr(x) cout<<#x<<" = "<<x<<" "
#define prln(x) cout<<#x<<" = "<<x<<endl
//#define pr(x) x
//#define prln(x) x
typedef long long LL;
const LL mod = 1e9 + 7;
int n, m;
int output[2][1000];
int get(int a,int b)//返回a~b之间的数字
{
return rand()%(b-a+1)+a;
}
void pg(int l , int r, int h, int p)
{
cout<<get(l,r)<<" "<<get(h,p)<<endl;
}
int ot1[10000],ot2[10000], ot3[10000],t;
int mp[100][100];
/*
2
3 3
4 6
2 3
3 4
1 3 0
2 3 1
3 3 1
3 2
3 5
1 3
3 4
2 2 0
2 3 0
*/
int main()
{
srand(time(0));
ios::sync_with_stdio(false);
int T=5;
cout <<T<<endl;
while (T--)
{
int n = 40;
t=0;
memset(mp,-1,sizeof(mp));
for (int i = 1; i <= rand()%71 ; ++ i) //穷举大概有多少约数
{
int a,b;
a=get(1,n);
b=get(1,n);
mp[a][b]=mp[b][a]=rand()%2;
}
for (int i = 1; i<=n;++i)
for (int j = i; j <= n; ++ j)
if (mp[i][j] !=-1)
{
++t;
ot1[t]=i;
ot2[t]=j;
ot3[t]=mp[i][j];
}
cout <<n<<" "<<t<<endl;
for (int i = 1; i <= n; ++ i)
{
LL x,y;
LL p=1e9;
x=((LL)rand()*(LL)rand())%p+1;
y=((LL)rand()*(LL)rand())%p+1;
if (x>y) swap(x,y);
if (x==y) y+=1;
cout<<x<<" "<<y<<endl;
}
for (int i = 1;i<=t;++i) cout<<ot1[i]<<" "<<ot2[i]<<" "<<ot3[i]<<endl;
}
return 0;
}