比较裸的$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】【树规(背包】【模拟】的更多相关文章

  1. 【10.29校内测试】【线段树】【DP】【二进制Trie树求最小值最大】

    Solution 标程太暴力惹QAQ 相当于是26棵线段树的说QAQ 不过我写了另一种写法,从大到小枚举每一个字母,标记字典序在这个字母之上的位置为1,每次都建一棵线段树,维护1的数量,即区间和. 修 ...

  2. 【10.10校内测试】【线段树维护第k小+删除】【lca+主席树维护前驱后驱】

    贪心思想.将a排序后,对于每一个a,找到对应的删除m个后最小的b,每次更新答案即可. 如何删除才是合法并且最优的?首先,对于排了序的a,第$i$个那么之前就应该删除前$i-1$个a对应的b.剩下$m- ...

  3. 【8.30校内测试】【找规律模拟】【DP】【二分+贪心】

    对于和规律或者数学有关的题真的束手无策啊QAQ 首先发现两个性质: 1.不管中间怎么碰撞,所有蚂蚁的相对位置不会改变,即后面的蚂蚁不会超过前面的蚂蚁或者落后更后面的蚂蚁. 2.因为所有蚂蚁速度一样,不 ...

  4. POJ 3345-Bribing FIPA(树状背包)

    题意: 有n个国家投票,要得到一个国家的投票有一定的花费,如果给到一个国家的票同时也得到了它所有附属国的票,给出国家关系树,求至少得到m票的最小花费. 分析:基础树状背包,dp[i][j],以i为根的 ...

  5. [HEOI2015]兔子与樱花 树规+贪心

    鬼能想到是个贪心.明明觉得是树规啊..又完美爆零.. 从叶子节点往上更新,能保证最优解(这块想了半天). 证明:当你的子树上有能删的点而你不删时,可能会对子树的根节点有利,最好的情况是使子树根节点由不 ...

  6. 【LibreOJ】#6396. 「THUPC2018」弗雷兹的玩具商店 / Toyshop 线段树+完全背包

    [题目]#6396. 「THUPC2018」弗雷兹的玩具商店 / Toyshop [题意]给定一个长度为n的物品序列,每个物品有价值.不超过m的重量.要求支持以下三种操作:1.物品价值区间加减,2.物 ...

  7. Codechef Black Nodes in Subgraphs(树型背包)

    题目链接 Black Nodes in Subgraphs 题目意思就是在一棵树中所有点标记为两种颜色(黑和白) 然后询问是否存在大小为X恰好有Y个黑点的连通块 这题我们可以用树型背包的方法 设$f[ ...

  8. HDU 1561:The more, The Better(有依赖的树型背包)

    http://acm.hdu.edu.cn/showproblem.php?pid=1561 题意:有n个点,容量为m,每个点有一个价值,还给出n条边,代表选第i个点之前必须先选ai,问最多的价值能取 ...

  9. 【10.7校内测试】【队列滑窗】【2-sat】【贪心+栈二分+线段树(noip模拟好题)】【生日祭!】

    比较好想的一道题,直接用队列滑窗,因为扫一遍往队列里加东西时,改变的只有一个值,开桶储存好就行了! #include<bits/stdc++.h> using namespace std; ...

随机推荐

  1. sublime出现卡顿的现象

    这几天,用sublime总是写一个代码就卡顿,卡卡卡,,,,要死的~ 最后,才发现是因为安装了一个插件:GitGutter插件,所以,小伙伴们请跟上我的节奏~~~~~ (1)Ctrl + Shift ...

  2. Git其他的命令------(四)

    git除了在工作当中可以进行对代码进行管理的设置之外,git的其他指令也偶尔会被用到~ 1:删除某一个文件:   rm -rf node,然后按下tab 2:查看修改文件的修改的详细信息:  git ...

  3. LOW逼三人组(三)----插入排序

    插入排序思路 插入排序算法: import random # 随机模块 import time def cal_time(func): # 装饰器 ,用来检测算法所执行的时间 def wrapper( ...

  4. qq上传文件进行测试要点分析

    功能 QQ 兼容性 1.Win系统/Mac系统  Android/IOS 品牌 传 1.上传方式:直接拖拽,按回车键上传 2.多个文件同时上传给一人/多人(考虑稳定性,是否存在内存泄露) 3.不是好友 ...

  5. 16级第二周寒假作业H题

    快速幂(三) TimeLimit:2000MS  MemoryLimit:128MB 64-bit integer IO format:%I64d Problem Description 计算( AB ...

  6. NASA: Seeing Jupiter(注视木星)

    This image of Jupiter’s southern hemisphere was captured by NASA’s Juno spacecraft on the outbound l ...

  7. VMvare 复制的数据库,需要改变的配置

    当我在VMware 上安装了一个linux虚拟机,同时在虚拟机上安装了一系列软件(包括数据库) 我们会修改hostname  ,修改后 对于数据库:我们要把/u01/app/oracle/produc ...

  8. JVM的分区+查看GC对象是否存活+3种GC算法+7种垃圾收集器+如何减少GC次数

    一.JVM的分区:   1.程序计数器(私有) 程序计数器是一块较小的内存分区,你可以把它看做当前线程所执行的字节码的指示器. 在虚拟机的概念模型里,字节码解释器工作时,就是通过改变计数器的值来选择下 ...

  9. ORACLE数据库导出导入数据

    准备工作: 1.登录管理员system 2.create directory dbdata as 'C:\oracle\tempData';--创建备份文件夹 3.grant read,write o ...

  10. U3D的一些常用基础脚本

    修改渲染颜色和贴图 1: var texture :Texture ; 2:  3: function Start () { 4: renderer.material.mainTexture = te ...