【9.2校内测试】【开学祭】【exgcd】【树规(背包】【模拟】

比较裸的$exgcd$的应用?
$exgcd$可以算出在$x$和$y$分别是最小正整数时的解。注意在这里因为有$a(x+\frac{b}{d})+b(y-\frac{a}{d})=c$,$d=gcd(a,b)$,所以$\frac{b}{d}$和$\frac{a}{d}$一定是整数,所以最小$x$的整数解%的应该是$\frac{b}{d}$而不是$b$,$y$同理。
算出两种情况的最小整数解后,$x$为最小正数时$x$一直在加,$y$一直在减,所以$x$最小时$y$都为非正数,则无解。判$y$时同理。这两种情况都排除后算出的$x$和$y$相当于是对应的最大$x$,$y$和最小$x$,$y$。算答案就用$x$大的减小的再除以$\frac{b}{d}$算得的就是其中一共有多少解。
最后就是要先判掉各种0的情况,避免$exgcd$中整除0或者$mod$0。
#include<iostream>
#include<cstdio>
#define LL long long
using namespace std; void exgcd ( LL a, LL b, LL &x, LL &y, LL &d ) {
if ( b == ) {
d = a; x = ; y = ;
return ;
}
LL x0, y0;
exgcd ( b, a % b, x0, y0, d );
x = y0;
y = x0 - ( a / b ) * y0;
} int main ( ) {
freopen ( "fuction.in", "r", stdin );
freopen ( "fuction.out", "w", stdout );
int T;
scanf ( "%d", &T );
while ( T -- ) {
LL a, b, c;
scanf ( "%I64d%I64d%I64d", &a, &b, &c );
if ( !a && !b && c ) { puts ( "" ); continue; }
if ( !a && !b && !c ) { puts("ZenMeZheMeDuo"); continue; }
if ( !a ) {
if ( c % b != || c / b < ) printf ( "0\n" );
else puts("ZenMeZheMeDuo");
continue;
} else if ( !b ) {
if ( c % a != || c / a < ) printf ( "0\n" );
else puts("ZenMeZheMeDuo");
continue;
}
if ( a < ) a = -a, b = -b, c = -c;
LL x, y, d;
exgcd ( a, b, x, y, d );
if ( c % d ) printf ( "0\n" );
else if ( b < ) { printf ( "ZenMeZheMeDuo\n" ); continue; }
else {
x *= c / d; y *= c / d; LL numy;
LL x1 = ( x % ( b / d ) + ( b / d ) ) % ( b / d );
if ( x1 == ) x1 += b / d;
LL y1 = ( c - x1 * a ) / b;
LL y2 = ( y % ( a / d ) + ( a / d ) ) % ( a / d );
if ( y2 == ) y2 += a / d;
LL x2 = ( c - y2 * b ) / a;
if ( y1 <= || x2 <= ) printf ( "0\n" );
else if ( ( x2 - x1 ) / ( b / d ) + > ) printf ( "ZenMeZheMeDuo\n" );
else printf ( "%I64d\n", ( x2 - x1 ) / ( b / d ) + );
}
}
return ;
}

一道以前就做过的经典树规+背包的题目。定义$dp[u][k]$表示$u$这棵子树内选择$k$个黑点能对答案产生的最大贡献。所以每次遍历子树时用背包的思想来计算当前连接到子树的边的贡献,更新子树的答案即可。
注意这里的初始化,最开始要把没有经过的状态定成-1,避免更新不存在的情况。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define LL long long
using namespace std; int n, m; void read ( int & x ) {
x = ; char ch = getchar ( );
while ( ch > '' || ch < '' ) ch = getchar ( );
while ( ch >= '' && ch <= '' ) {
x = x * + ch - ''; ch = getchar ( );
}
} struct Node {
int v, nex; LL w;
Node ( int v = , LL w = , int nex = ) :
v ( v ), w ( w ), nex ( nex ) { }
} Edge[]; int h[], stot;
void add ( int u, int v, LL s ) {
Edge[++stot] = Node ( v, s, h[u] );
h[u] = stot;
} int siz[];
LL dp[][];
void Dfs ( int u, int f ) {
siz[u] = ;
memset ( dp[u], -, sizeof ( dp[u] ) );
dp[u][] = , dp[u][] = ;
for ( RG int i = h[u]; i; i = Edge[i].nex ) {
int v = Edge[i].v;
if ( v == f ) continue;
Dfs ( v, u );
siz[u] += siz[v];
for ( RG int j = min ( siz[u], m ); j >= ; j -- )
for ( RG int k = ; k <= min ( siz[v], j ); k ++ ) {
LL tmp = 1LL * Edge[i].w * ( 1LL * k * ( m - k ) + 1LL * ( siz[v] - k ) * ( n - m - siz[v] + k ) );
tmp += dp[v][k];
if ( dp[u][j-k] != - ) dp[u][j] = max ( dp[u][j], dp[u][j-k] + tmp );
}
} } int main ( ) {
freopen ( "coloration.in", "r", stdin );
freopen ( "coloration.out", "w", stdout );
scanf ( "%d%d", &n, &m );
for ( int i = ; i < n; i ++ ) {
int u, v, s;
read ( u ); read ( v ); read ( s );
add ( u, v, s );
add ( v, u, s );
}
Dfs ( , );
printf ( "%I64d", dp[][m] );
return ;
}

把方向搞错了以至于现在不是很想写!!!
以下粘的题解:
光线只有遇上边界或堵塞的格子才会改变方向,所以改变方向的位置是有限的,光线的方向又最多只有四种,所以光线在循环之前改变方向的次数是$O(n+m+k)$级别的。我们可以模拟光线的移动。已知光线位置和光线的方向,使用二分的方法可以在$O(log k)$的时间复杂度内求出即将改变方向的位置和改变后的方向。
我们暂把光线的位置和方向称为光线的状态。一种状态能转移到一种且仅有一种状态。如果从状态$a$能转移到状态$b$,那么$b$反向后的状态能转移到$a$反向后的状态。所以一种状态能从一种且仅有一种状态转移而来。这就像是一种置换,所以从初始状态出发,必定会回到初始状态,并且回到初始状态之前不会重复经过某种状态。
我们对网格进行染色,有邻边的格子颜色不同,形成一个二分图。根据题目中光线反射的方式,可以发现,每当光线沿西北、东南方向前进时,只会经过一种颜色的网格,每当光线沿东北、西南方向前进时,只会经过另一种颜色的网格。所以光线在某一个格子中心时,要么只会是西北、东南方向之一,要么只会是东北、西南方向之一。
这样,如果一次循环内一个格子被重复经过,只有可能是光线以相反的两个方向进入,并且一次循环内一个格子最多被经过两次。一个格子被经过两次,所有被光线经过的格子都会被经过两次。易知,如果光线在前进过程中出现过如下两种反射,所有格子就会被经过两次。只需在模拟的过程中记录是否出现过这两种情况即可。

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int N=;
int n,m,k,dx,dy,x,y;
long long ans;
bool f;
char ch[];
struct qwe
{
int x,y;
qwe(int X=,int Y=)
{
x=X,y=Y;
}
bool operator < (const qwe &b) const
{
return x<b.x||(x==b.x&&y<b.y);
}
};
vector<qwe>a[];
int read()
{
int r=,f=;
char p=getchar();
while(p>''||p<'')
{
if(p=='-')
f=-;
p=getchar();
}
while(p>=''&&p<='')
{
r=r*+p-;
p=getchar();
}
return r*f;
}
void add(int x,int y)
{
a[].push_back(qwe(x-y,x));
a[].push_back(qwe(x+y,x));
}
void wk()
{
int fl=(dx!=dy);
qwe p=fl?qwe(x+y,x):qwe(x-y,x);
vector<qwe>::iterator it=upper_bound(a[fl].begin(),a[fl].end(),p);
for(;it->x!=p.x;it--);
if(dx<)
for(;it->y>=x;it--);
ans+=abs(x-it->y)-;
x=it->y,y=fl?it->x-x:x-it->x;
bool u=binary_search(a[].begin(),a[].end(),qwe(x-y-dx,x-dx)),v=binary_search(a[].begin(),a[].end(),qwe(x-y+dy,x));
if(u==v)
f=,dx*=-,dy*=-;
else if(u)
x-=dx,dy*=-;
else if(v)
y-=dy,dx*=-;
}
int main()
{
freopen("ray.in","r",stdin);
freopen("ray.out","w",stdout);
n=read(),m=read(),k=read();
for(int i=;i<=m;i++)
add(,i),add(n+,i);
for(int i=;i<=n+;i++)
add(i,),add(i,m+);
for(int i=;i<=k;i++)
{
int x=read(),y=read();
add(x,y);
}
x=read(),y=read();
scanf("%s",ch);
dx=(ch[]=='N')?-:,dy=(ch[]=='W')?-:;
sort(a[].begin(),a[].end());
sort(a[].begin(),a[].end());
wk();
int sx=x,sy=y,sdx=dx,sdy=dy;
ans=;
do
wk();
while(!(x==sx&&y==sy&&dx==sdx&&dy==sdy));
printf("%I64d\n",(f)?(ans>>):ans);
return ;
}
【9.2校内测试】【开学祭】【exgcd】【树规(背包】【模拟】的更多相关文章
- 【10.29校内测试】【线段树】【DP】【二进制Trie树求最小值最大】
Solution 标程太暴力惹QAQ 相当于是26棵线段树的说QAQ 不过我写了另一种写法,从大到小枚举每一个字母,标记字典序在这个字母之上的位置为1,每次都建一棵线段树,维护1的数量,即区间和. 修 ...
- 【10.10校内测试】【线段树维护第k小+删除】【lca+主席树维护前驱后驱】
贪心思想.将a排序后,对于每一个a,找到对应的删除m个后最小的b,每次更新答案即可. 如何删除才是合法并且最优的?首先,对于排了序的a,第$i$个那么之前就应该删除前$i-1$个a对应的b.剩下$m- ...
- 【8.30校内测试】【找规律模拟】【DP】【二分+贪心】
对于和规律或者数学有关的题真的束手无策啊QAQ 首先发现两个性质: 1.不管中间怎么碰撞,所有蚂蚁的相对位置不会改变,即后面的蚂蚁不会超过前面的蚂蚁或者落后更后面的蚂蚁. 2.因为所有蚂蚁速度一样,不 ...
- POJ 3345-Bribing FIPA(树状背包)
题意: 有n个国家投票,要得到一个国家的投票有一定的花费,如果给到一个国家的票同时也得到了它所有附属国的票,给出国家关系树,求至少得到m票的最小花费. 分析:基础树状背包,dp[i][j],以i为根的 ...
- [HEOI2015]兔子与樱花 树规+贪心
鬼能想到是个贪心.明明觉得是树规啊..又完美爆零.. 从叶子节点往上更新,能保证最优解(这块想了半天). 证明:当你的子树上有能删的点而你不删时,可能会对子树的根节点有利,最好的情况是使子树根节点由不 ...
- 【LibreOJ】#6396. 「THUPC2018」弗雷兹的玩具商店 / Toyshop 线段树+完全背包
[题目]#6396. 「THUPC2018」弗雷兹的玩具商店 / Toyshop [题意]给定一个长度为n的物品序列,每个物品有价值.不超过m的重量.要求支持以下三种操作:1.物品价值区间加减,2.物 ...
- Codechef Black Nodes in Subgraphs(树型背包)
题目链接 Black Nodes in Subgraphs 题目意思就是在一棵树中所有点标记为两种颜色(黑和白) 然后询问是否存在大小为X恰好有Y个黑点的连通块 这题我们可以用树型背包的方法 设$f[ ...
- HDU 1561:The more, The Better(有依赖的树型背包)
http://acm.hdu.edu.cn/showproblem.php?pid=1561 题意:有n个点,容量为m,每个点有一个价值,还给出n条边,代表选第i个点之前必须先选ai,问最多的价值能取 ...
- 【10.7校内测试】【队列滑窗】【2-sat】【贪心+栈二分+线段树(noip模拟好题)】【生日祭!】
比较好想的一道题,直接用队列滑窗,因为扫一遍往队列里加东西时,改变的只有一个值,开桶储存好就行了! #include<bits/stdc++.h> using namespace std; ...
随机推荐
- php的发展历史
php最初就是为了快速构建一个web页面而迅速被大家广为接受的.它的好处是在代码中能内嵌html的代码,从而让程序员能再一个页面中同时写html代码和php代码就能生成一个web页面. 这篇文章用时间 ...
- 常见踩坑案例(一) subList引起FULLGC
计划真的赶不上变化,时间过得真快.废话不多说了,今天主要记录之前有同事遇到的一些坑分享出来. 一.封装类的应用会引起NPE异常 对于其他对象的应用,一般在使用之前会判断它是否为空,如果不为空才会使用它 ...
- 一. Jmeter--使用代理录制脚本
Jmeter脚本是以.JMX格式为主 1. Jmeter也是支持录制的,支持第三方录制方式和代理录制方式. (1).第三方录制主要是通过badboy来录制,录制后另存为jmx格式即可. (2).Jme ...
- ogg数据初始化历程记录
之前,源端数据表结构发生改变,不知道前面的同事是怎么搞得(生成的数据定义文件不对,还是没有把进程启动),造成进程停止20天,然后重启复制进程,对比源端和目标端数据有差异(总共差10000多条数据),问 ...
- discuz 积分按日重新计算,(摒弃以前24小时计算)
修改\source\module\forum\forum_misc.php将 foreach(C::t('forum_ratelog')->fetch_all_sum_score($_G['ui ...
- ubuntu sougou输入法
1, 打开搜狗输入法Linux版的官网http://pinyin.sogou.com/linux/?r=pinyin,并下载你需要的版本,这里选择64位版. 2,在Ubuntu14.01下可以直接点击 ...
- PowerPC简单了解
PowerPC相对于ARM优势: Powerpc芯片凭借其出色的性能和高度整合和技术先进特性在网络通信应用,工业控制应用,家用数字化,网络存储领域,军工领域,电力系统控制等都具有非常广泛的应用.由于P ...
- MySQL Warning: Using a password on the command line interface can be insecure.解决办法
转自 http://www.cnblogs.com/sunss/p/6256706.html 被一个小朋友问到,直接公布答案: If your MySQL client/server version ...
- OAuth认证与授权
什么是OAuth授权? 一.什么是OAuth协议 OAuth(开放授权)是一个开放标准. 允许第三方网站在用户授权的前提下访问在用户在服务商那里存储的各种信息. 而这种授权无需将用户提供用户名和密 ...
- ios 不支持iframe 解决方案
在iframe外层在包一层,通过appendChild()把内容增加到容器中,完整代码如下: @section Css { <link href="@ViewHelper.Conten ...