2019.7.4 JZ DAY10总结

D A Y 1 DAY 1 DAY1

T 1 T1 T1
非 回 文 数 字 非回文数字

Description
如果一个字符串从后往前读与从前往后读一致,我们则称之为回文字符串。当一个数字不包含长度大于1的子回文数字时称为非回文数字。例如,16276是非回文数字,但17276不是,因为它包含回文数字727。
你的任务是在一个给定的范围内计算非回文数字的总数。

Input
输入仅一行,包含两个整数a和b。

Output
输出仅一行,包含一个整数,表示a到b范围内(包括a和b)非回文数字的总数。

Sample Input
输入1:
123 321

输入2:
123456789 987654321

Sample Output
输出1:
153

输出2:
167386971

Data Constraint
25%的数据:b-a<=100 000.
100%的数据:0<=a<=b<=10^18

毕竟没怎么打过数位dp,考场直接上暴力,26分,非常不优秀。那些会数位dp的大佬们,听说都只用了二十分钟不到就直接切了,%%%%%%%%%%%%%。今天也算是比较透彻地自学了数位dp,发现其实也并不是很难。这题设 f [ i ] [ j ] [ k ] [ p ] f[i][j][k][p] f[i][j][k][p]表示当前第i位,第i - 1位位j,第i - 2位为k,p为01状态,意思是1为有前导零,0为没有,时的方案书。那么手玩转移。我打的是记忆化搜索。

#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;

ll a,b,num[20],f[20][11][11][3];

ll dfs(int len,int l1,int l2,int zero,int top)
{
	if (!len) return zero ^ 1;
	if (!top && ~f[len][l1][l2][zero]) return f[len][l1][l2][zero];
	ll res = 0;
	int mx = top ? num[len] : 9;
	for (int i = 0; i <= mx; i ++)
		if (i != l1 && i != l2)
			res += dfs(len - 1,zero && (i == 0) ? 10 : i,l1,zero && (i == 0),top && i == num[len]);
	if (!top) f[len][l1][l2][zero] = res;
	return res;
}

ll solve(ll x)
{
	if (x <= 0) return 0ll;
	int len = 0;
	while (x) {num[++ len] = x % 10; x /= 10;}
	return dfs(len,10,10,1,1);
}

int main()
{
	memset(f,-1,sizeof f);
	scanf("%lld%lld",&a,&b);
	printf("%lld",solve(b) - solve(a - 1) + (a == 0));
	return 0;
}

T 2 T2 T2
管 道 管道

Description
Hotham市再次被Jester袭击。这一次,Jester攻击的目标是Hotham的供水系统。Hotham的淡水存储在N个水库,由M个管道连接。
任意2个水库之间至少有一条路径,该路径可能包含多个管道。每个管道连接两个不同的水库,任何两个水库之间最多只有一个管道。Jester破坏了一些管道进行排水。管道的排水量为偶数立方米/秒。如果连接水库u和水库v的管道排水量为2D立方米/秒,那么水库u和水库v排水量分别为D立方米/秒。Jester可以也破坏一些管道进行注水。同样,连接水库u和v的管道注入水量为2P立方米/秒,则水库u和水库v注水量分别为P立方米/秒。
每个水库供水量的净变化是由连接到它的管道的排水量和注水量的总和。如果连接该水库的管道排水量分别为2D1, 2D2,…,2Da立方米/秒, 注水量分别为2P1, 2P2 ,…,2Pb 立方米/秒。该水库水量的净变化为P1 + P2 + … + Pb -D1 - D2 –Da。
Hotham市长已在水库安装了传感器,但不是在管道中。因此,他可以观察到在每个水库水的净变化,但并知道有多少水被排出或注入各个管道。
给出水管连接图和每个水库供水量的净变化,编写程序决定这些信息是否能确定一个唯一的计划。如果各个水管排出或注入的水量是唯一的,那么该计划可以被唯一确定。请注意,并不是每一个水管中的注水量和排水量都相等。如果恰好有一个可能性,你的程序应该打印出来。

Input
输入的第一行包含两个整数:N:Hotham的水库数 和M:管道数。
接下来的N行每行包含一个整数ci:表示水库i(1≤i≤N)的水量净变化。
再接下来的M行每行包含两个整数ui和vi(1≤i≤M)。每一行分别表示,水库 ui和vi之间有管道连接(1≤ui,vi≤N)。

Output
如果Jester的计划不能被唯一确定,你的程序则输出0。否则,你的程序应该输出M行,每一行包含一个整数Xi(1≤i≤M)。 如果Jester从连接水库ui和vi间的管道里排水,该管道的排水量为di立方米/秒,则设Xi=-di。如果Jester往连接水库ui和vi间的管道里注水,该管道的注水量为pi立方米/秒,则Xi=pi。如果Jester对连接水库ui和vi间的管道既不排水也不注水,则Xi =0。

Sample Input
输入1:
4 3
-1
1
-3
1
1 2
1 3
1 4

输入2:
4 5
1
2
1
2
1 2
2 3
3 4
4 1
1 3

Sample Output
输出1:
2
-6
2

输出2:
0

Data Constraint
1<=N<=100 000
1<=M<=500 000
-109<=Ci<=109
如果方案唯一,则-109<=Xi<=109
30%的数据满足供水系统的网络是一棵树。

呃,审完题后就直接打了30%的树的情况,很简单很暴力,然后剩下直接输出了0,拿了72pts,不给过听说是可以拿到78pts的,也不知道哪里打错了。考场时考虑到了方程思想,但是并不知道怎么推算,然后就放弃了。现在也不是很想改,因为想学点其他算法,姑且就先把早上考场的代码放上了。

#include <cstdio>
#include <queue>
using namespace std;

const int maxn = 1e5 + 10;
const int maxm = 5e5 + 10;
struct Edge{
	int to,next;
} f[maxm << 1];
int n,m,v[maxn],rd[maxn],root,fa[maxn],head[maxn],cnt,a[maxn],b[maxn],dis[maxn];
queue <int> q;

int read()
{
	int x = 0,w = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {if (ch == '-') w = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
	return x * w;
}

void add(int u,int v)
{
	f[++ cnt].to = v;
	f[cnt].next = head[u];
	head[u] = cnt;
}

void dfs(int now)
{
	for (int i = head[now],v; i; i = f[i].next)
	{
		v = f[i].to;
		if (v == fa[now]) continue;
		dfs(v);
	}
	dis[now] = v[now] * 2;
	v[fa[now]] -= v[now];
}

int main()
{
	n = read(),m = read();
	for (int i = 1; i <= n; i ++) v[i] = read();
	for (int i = 1; i <= m; i ++) a[i] = read(),b[i] = read(),rd[b[i]] ++,add(a[i],b[i]),add(b[i],a[i]);
	for (int i = 1; i <= n; i ++) if (!rd[i]) {root = i;break;}
	if (m != n - 1)
	{
		printf("%d",0);
		return 0;
	}
	q.push(root);
	while (!q.empty())
	{
		int u = q.front();
		q.pop();
		for (int i = head[u],v; i; i = f[i].next)
		{
			v = f[i].to;
			if (v == fa[u]) continue;
			fa[v] = u;
			q.push(v); 
		}
	}
	dfs(root);
	if (v[root] != 0) 
	{
		printf("%d",0);
		return 0;	
	} else
	{
		for (int i = 1; i <= m; i ++)
		{
			if (fa[a[i]] == b[i]) printf("%d\n",dis[a[i]]); else printf("%d\n",dis[b[i]]);
		}
	}
	return 0;
}

T 3 T3 T3
牛 棚 安 排 牛棚安排

Description
Farmer John的N(1<=N<=1000)头奶牛分别居住在农场所拥有的B(1<=B<=20)个牛棚的某一个里。有些奶牛很喜欢她们当前住的牛棚,而另一些则讨厌再在它们现在所在的牛棚呆下去。
FJ在忍受了若干次奶牛的抱怨后,决定为所有奶牛重新安排牛棚,使最不满的那头奶牛与最高兴的奶牛的心情差异最小,即使这会让所有奶牛都更加郁闷。
每头奶牛都把她对各个牛棚的好感度从高到低排序后告诉了FJ。当然,如果一头奶牛被安排到的牛棚在她给出的列表中越靠后,她就会越郁闷。你可以认为奶牛的郁闷指数是她被分配到的牛棚在列表中的位置。奶牛们是斤斤计较的,她们无法容忍别的奶牛在自己喜欢的牛棚里快乐地生活,而自己却呆在一个自己不喜欢的牛棚里。每个牛棚都只能容纳一定数量的奶牛。FJ希望在每个牛棚都没有超出容量限制的前提下,使最郁闷和最高兴的奶牛的郁闷指数的跨度最小。
FJ请你帮他写个程序,来计算这个最小的郁闷指数跨度到底是多少。

Input
第1行: 包含2个用空格隔开的整数N和B,分别表示牛和牛棚的数量
第2…N+1行: 每行包含B个用空格隔开的整数,刚好完全包含1…B的整数。第i+1行的第一个整数,表示奶牛i最喜欢的牛棚编号。第二个整数表示奶牛i的列表中排在第二位,也就是她第二喜欢的牛棚。依此类推。
第N+2行: 包含B个用空格隔开的整数,第i个整数表示牛棚i最多能容纳的奶牛的数目。所有牛棚能容纳奶牛头数的和至少是N。

Output
第1行: 输出一个整数,表示所有奶牛中最高兴与最郁闷的牛的郁闷指数跨度

Sample Input
6 4
1 2 3 4
2 3 1 4
4 2 3 1
3 1 2 4
1 3 4 2
1 4 2 3
2 1 3 2

Sample Output
2

Hint
【样例说明】
每头奶牛都能被安排进她的第一或第二喜欢的牛棚。下面给出一种合理的分配方案:奶牛1和奶牛5住入牛棚1,牛棚2由奶牛2独占,奶牛4住进牛棚3,剩下的奶牛3和奶牛6安排到牛棚4。

考场没想到用网络流,于是直接交了一个爆搜,奇迹般地拿到了62.5pts,不过由于被自己后面交的程序覆盖了,最后只有25pts,唉真是可惜。正解十分暴力,网络流暴力连边,然后dinic就ok了。

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

const int maxn = 1e3 + 500;
const int maxb = 100;
const int inf = 0x3f3f3f3f;
struct Edge{
	int to,next,val;
} f[maxn * maxb * 2 + 10];
int n,b,a[maxn][maxb],sp[maxb],l,r,head[maxn + maxb + 10],s,t,dep[maxn + maxb + 10],cnt,ans;

int min(int a,int b) {return a < b ? a : b;}

int read()
{
	int x = 0,w = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {if (ch == '-') w = -1;ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}
	return x * w;
}

void add(int u,int v,int w)
{
	f[++ cnt].to = v;
	f[cnt].val = w;
	f[cnt].next = head[u];
	head[u] = cnt;
}

queue <int> q;

bool bfs()
{
	while (!q.empty()) q.pop();
	memset(dep,0,sizeof dep);
	dep[s] = 1;
	q.push(s);
	while (!q.empty())
	{
		int u = q.front();
		q.pop();
		for (int i = head[u],v; ~i; i = f[i].next)
		{
			v = f[i].to;
			if (dep[f[i].to] || !f[i].val) continue;
			dep[v] = dep[u] + 1;
			q.push(v);
		}
	}
	if (dep[t]) return 1; else return 0;
}

int dfs(int u,int lim)
{
	if (!lim || u == t) return lim;
	int flow = 0;
	for (int i = head[u],v; ~i; i = f[i].next)
	{
		v = f[i].to;
		if (dep[v] != dep[u] + 1 || !f[i].val) continue;
		int di = dfs(v,min(lim,f[i].val));
		if (di)
		{
			lim -= di;
			flow += di;
			f[i].val -= di;
			f[i ^ 1].val += di;
			if (!lim) break;
		}
	}
	return flow;
}

int dicnic()
{
	int res = 0;
	while (bfs())
		res += dfs(s,inf); 
	return res;
}

bool check(int l,int r)
{
	memset(head,-1,sizeof head);
	cnt = -1;
	for (int i = 1; i <= n; i ++)
		add(s,i + 1,1),add(i + 1,s,0);
	for (int i = 1; i <= n; i ++)
		for (int j = l; j <= r; j ++)
			add(i + 1,a[i][j] + n + 1,1),add(a[i][j] + n + 1,i + 1,0);
	for (int i = 1; i <= b; i ++)
		add(i + n + 1,t,sp[i]),add(t,i + n + 1,0);	
	if (dicnic() == n) return 1; else return 0;
}

int main()
{
	n = read(),b = read();
	ans = b;
	for (int i = 1; i <= n; i ++)
		for (int j = 1; j <= b; j ++)
			a[i][j] = read();
	for (int i = 1; i <= b; i ++) sp[i] = read();
	s = 1,t = n + b + 2;
	for (int i = 1; i <= b; i ++)
	{
		for (int j = i; j <= b; j ++)
		{
			if (j - i + 1 >= ans) break;
			if (check(i,j)) {ans = j - i + 1;break;}
		}
		if (ans == b) break;
	}
	printf("%d",ans);
	return 0;
}

不知道为什么,我的网络流慢得飞起。


今天分数26 + 72 + 25 = 123,又是被爆踩的一天。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值