Day 2

rank 11 100+35+30=165

本题是一道数论题,求ax+by=c的正整数对(x,y) x>=0并且y>=0

先说下gcd: 求a,b公约数gcd(a,b)

如gcd(4,6)=  2

辗转相除法 gcd(a,b)=gcd(b,a%b)

证明一下,令a=kb+r,那么r=a%b;

设d为(a,b)的一个任意公约数d,所以d|a且d|b

因为r=a-kb因为d|a且d|b,所以d|r注意到我们的d是任意选取的,

那么最大公约数是属于这个公因数集合里的所以gcd(a,b)=gcd(b,a%b)

再说下ex_gcd(a,b,&x,&y)求ax+by=gcd(a,b)的一个整数解 x,y

算法如下:

b=0时gcd(a,b)=gcd(a,0)=a;所以ax=a,所以x=1,y=任意数(这里赋值为0)

ax1+by1=gcd(a,b)=gcd(b,a%b)=bx2+(a%b)y2

引理: a-[a/b]*b=a%b

令a=br+k,左边=br+k-[(br+k)/b]*b=br+k-br=k=a%b=右边

由引理得:ax1+by1=bx2+(a-[a/b]*b)y2=ay2+b(x2-[a/b*b]y2)

由恒等式定理得: x1=y2,y1=x2-[a/b*b]y2

所以求解(x1,y1)只要求出(x2,y2)就可以了

ex_gcd程序如下:

ll ex_gcd(ll a,ll b,ll &x,ll &y)
{
if (b==) { x=;y=; return a;}
ll r=ex_gcd(b,a%b,x,y);
ll t=x;x=y;y=t-a/b*y;
return r;
}

但是这只是求出一组解但我们要求多组解甚至解的个数

令一组解(x0,y0)是初始解 (x1,y1)是要求的解

ax0+by0=gcd(a,b)=ax1+by1

a(x0-x1)=b(y1-y0)两边同时除以gcd(a,b)

设gcd(a,b)=g;a'=a/g;b'b/g

那么就可以写成 a'(x0-x1)=b'(y1-y0) 因为g为a,b最大公约数

那么 a'和b'互质

那么b'|(x0-x1);a'|(y1-y0)设x0-x1=kb'那么y1-y0=ka'

所以x1=x0-kb';y1=y0+ka' k为整数

由此可见方程ax+by=gcd(a,b)如果有解那么一定有无线组解

(x0,y0)==>(x0-kb',y0+ka')

对于一般2元1次不等式ax+by=c若c%gcd(a,b)!=0那么一定无解否则一定有多组解

回到题目让我们求出ax+by=c,通过上面那句话就可以轻易判断有无解,现在考虑解的个数

先把x0 y0调整到正数

x最小时且大于0,y最大,x0-kb'>=0不停的增加k最多可以是kmax= x0/b';xmin=x0-(x0/b')*b'=x0%b'

x最大时y最小且大于0,y0+ka'>=0不停的减去k最多可以是kmin=-y0/a'同理ymin=y0%a'

通过ymin可以求出xmax(带入即可)

求出xmin和xmax后再xmin和xmax之间每隔b‘就有一组解所以就是一个等差数列,个数是(尾项-首相)/公差+1=(xmax-xmin)/b'+1

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ex_gcd(ll a,ll b,ll &x,ll &y)
{
if (b==) { x=;y=; return a;}
ll r=ex_gcd(b,a%b,x,y);
ll t=x;x=y;y=t-a/b*y;
return r;
}
inline ll read()
{
ll X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
int main()
{
freopen("cake.in","r",stdin);
freopen("cake.out","w",stdout);
int T; scanf("%d",&T);
while (T--) {
ll a=read(),b=read(),x,y,c=read();
ll g=ex_gcd(a,b,x,y);
if (c%g!=) {
printf("0\n");
continue;
}
ll g1=a/g,g2=b/g;ll k=c/g;
x=x*(k%g2); y=y*(k%g1); //后面反正要%g1的现在先%防止爆炸
ll xmin=(x%g2+g2)%g2,ymin=(y%g1+g1)%g1;
ll xmax=(c-b*ymin)/a; //通过ymin求xmax
if (xmax-xmin<) {
printf("0\n"); continue;
}
ll ans=((xmax-xmin)/g2)+;//等差数列个数
printf("%lld\n",ans);
}
return ;
}

30pts:

# include <bits/stdc++.h>
using namespace std;
char s[];
bool fun(int z,int a,int c,int k,int m,int n)
{
for (int i=;i<=n;i++) {
z=((a*z+c)/k)%m;
if ((z<m/)&&(s[i]!='')) return false;
else if ((z>=m/)&&(s[i]!=''))return false;
}
return true;
}
int main()
{
freopen("zero.in","r",stdin);
freopen("zero.out","w",stdout);
int a,c,k,m,n;
scanf("%d%d%d%d%d",&a,&c,&k,&m,&n);
scanf("%s",s+);
int ans=;
for(int z=;z<=m;z++) {
if (fun(z,a,c,k,m,n)) ans++;
}
printf("%d\n",ans);
return ;
}

100pts:倍增+hash

题解原文:

倍增HASH,用倍增记录每个值跳2^i次后会到哪个值,构成的串的HASH值,

然后根据n的二进制直接算答案就行了,倍增的时候要滚存。

#include <bits/stdc++.h>

using namespace std;

const int mo1 = ;
const int mo2 = ;
const int base1 = ;
const int base2 = ;
const int M = ;
const int N = ; vector<int>a[M];
pair<int, int>HASH;
int to[M][], Pow1[N], Pow2[N], now[M];
pair<int, int>Hash[M][], nowhash[M];
int ans;
char s[N]; inline void Ch(pair<int, int> &now, int C)
{
now.first = 1ll * now.first * Pow1[C] % mo1;
} inline void Add(pair<int, int> &now, pair<int, int> A)
{
now.first = now.first + A.first;
if(now.first >= mo1)now.first -= mo1;
} inline int check(pair<int, int> a, pair<int, int> b)
{
return ((a.first == b.first) && (a.second == b.second));
} int main()
{
freopen("zero.in", "r", stdin);
freopen("zero.out", "w", stdout);
int A, c, k, m, n;
Pow1[] = Pow2[] = ;
scanf("%d%d%d%d%d", &A, &c, &k, &m ,&n);
for(int i = ;i <= n;i++)
{
Pow1[i] = 1ll * Pow1[i - ] * base1 % mo1;
}
int M = m >> ;
for(int i = ;i < m;i++)
{
int z = i;
now[i] = i;
z = ((1ll * A * z + c) / k) % m;
to[i][] = z;
Hash[i][].first = (z >= M) + ;
}
scanf("%s", s);
if(n & )
{
for(int i = ;i < m;i++)
{
nowhash[i] = Hash[now[i]][];
now[i] = to[now[i]][];
}
}
for(int i = ;i < n;i++)
{
HASH.first = (1ll * HASH.first * base1 + s[i] - '' + ) % mo1;
} for(int x = ;x <= ;x++)
{
for(int i = ;i < m;i++)
{
to[i][x & ] = to[to[i][(x - ) & ]][(x - ) & ];
Hash[i][x & ] = Hash[i][(x - ) & ];
Ch(Hash[i][x & ], << (x - ));
Add(Hash[i][x & ], Hash[to[i][(x - ) & ]][(x - ) & ]);
}
if(n & ( << x))
{
for(int i = ;i < m;i++)
{
Ch(nowhash[i], << x);
Add(nowhash[i], Hash[now[i]][x & ]);
now[i] = to[now[i]][x & ];
}
}
}
for(int i = ;i < m;i++)
if(check(nowhash[i], HASH))ans++;
printf("%d\n", ans);
}

题意:

给一个DAG,选择尽量多的点使彼此之间不存在祖先-后代关系。

5%:

暴力枚举每一个点是否被选中,时间复杂度:O(2^n)

20%:

在上一个做法的基础上加上一些剪枝。时间复杂度:O(2^n)。

此算法亦可通过n==200的测试点,且只需要16ms(luogu上)。

树的部分分:

容易发现选择全部叶节点即可。时间复杂度:O(n)

“每个会员要么没有上司,要么没有下属”的:

容易发现此时的DAG是一个二分图。使用经典的二分图最大独立集算法(点数-最大匹配数)即可。时间复杂度:O(m*sqrt(n))。

“全是直接下属”的:

我也不知道怎么做,这个部分分只是为了让***的错误算法多拿一些分。

100%:

容易发现此题是一道DAG最大独立集裸题(参见 CTSC2008祭祀),而且不用输出方案。(但我真的不是出的原题,纯属巧合)

由于时间原因,在此复制@白苏小公子喵 的题解:

在有向无环图中,我们定义:

链:图上一些点的集合,对于链上任意两个点x、y,满足x能到达y或者y能到达x。

反链:图上一些点的的集合,对于反链上任意两个点x、y,满足x不能到达y并且y不能到达x。

所以就是很显然的求最长反链长度了~

有以下Dilworth定理:

最长反链长度=最小链覆盖(选取最少的链覆盖所有的点)->证明详见最长反链与最小链覆盖

以及其对偶定理:最长链长度=最小反链覆盖

所以就又转化成了求最小路径(链)覆盖了,来看怎么求:

选择建一个二分图,两边各有n个点,原来的点node分别对应两个图中的node1、node2。如果原图中存在边 x->y,那么就在二分图上建立边 x1->y2。

跑一遍匈牙利,则有 原图最小路径覆盖=原点数n-二分图最大匹配

(当然也可以用网络流,则有 原图最小路径覆盖=原点数n-最大流)

为什么呢?考虑每在二分图上连一条边,就相当于将两条路径连成一条,那么最小链覆盖数就减少了1(少用一条链覆盖所有点了)。我们将一个点拆成两个,跑二分图最大匹配,避免了路径相交的问题,保证所选出来的每一条一定为一条链。

#include<bits/stdc++.h>
#define maxn 10010
#define int64 long long
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
using namespace std;
bitset<maxn> isfa[maxn];
int n,m,que[maxn],cnt;
int ind[maxn],top[maxn];
vector<int> v[maxn],vb[maxn];
struct edge{
int u,v,cap;
};
struct Dinic{
int n,s,t,dis[maxn],cur[maxn],que[maxn];
vector<edge>e;vector<int>v[maxn];
void Init(int n){
this->n=n;e.clear();
for(int i=;i<n;i++)v[i].clear();
}
void AddEdge(int x,int y,int flw){
e.push_back((edge){x,y,flw});
e.push_back((edge){y,x,});
v[x].push_back(e.size()-);
v[y].push_back(e.size()-);
}
int bfs(){
memset(dis,0x3f,sizeof dis);
int l=,r=;que[]=s;dis[s]=;
while(l<=r){
int p=que[l++],to,i;
for(int t=;t<(int)v[p].size();++t)if(e[i=v[p][t]].cap && dis[to=e[i].v]>1e9)
dis[to]=dis[p]+,que[++r]=to;
}
return dis[t]<1e9;
}
int dfs(int p,int a){
if(p==t || !a)return a;
int sf=,flw;
for(int &i=cur[p],to;i<(int)v[p].size();++i){
edge &E=e[v[p][i]];
if(dis[to=E.v]==dis[p]+ && (flw=dfs(to,min(a,E.cap)))){
E.cap-=flw;e[v[p][i]^].cap+=flw;
a-=flw;sf+=flw;
if(!a)break;
}
}
return sf;
}
int dinic(int s,int t){
this->s=s;this->t=t;
int flw=;
while(bfs()){
memset(cur,,sizeof cur);
flw+=dfs(s,1e9);
}
return flw;
}
}sol;
int main(){
FO(dance);
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
v[x].push_back(y);ind[y]++;
vb[y].push_back(x);
}
int l=,r=;
for(int i=;i<=n;i++)if(!ind[i])que[++r]=i;
while(l<=r){
int now=que[l++];top[++cnt]=now;
for(int i=;i<(int)v[now].size();i++)
if(!--ind[v[now][i]])que[++r]=v[now][i];
}
for(int i=;i<=n;i++){
int p=top[i];isfa[p][p]=;
sol.AddEdge(,i*,);
sol.AddEdge(i*+,,);
for(int j=;j<(int)vb[p].size();j++)
isfa[p]|=isfa[vb[p][j]];
for(int j=;j<=n;j++)if(isfa[p][j] && p!=j)
sol.AddEdge(j*,p*+,);
}
printf("%d\n",n-sol.dinic(,));
return ;
}

HGOI20180815 (NOIP 提高组模拟赛 day2)的更多相关文章

  1. 【洛谷】NOIP提高组模拟赛Day2【动态开节点/树状数组】【双头链表模拟】

    U41571 Agent2 题目背景 炎炎夏日还没有过去,Agent们没有一个想出去外面搞事情的.每当ENLIGHTENED总部组织活动时,人人都说有空,结果到了活动日,却一个接着一个咕咕咕了.只有不 ...

  2. l洛谷 NOIP提高组模拟赛 Day2

    传送门 ## T1 区间修改+单点查询.差分树状数组. #include<iostream> #include<cstdio> #include<cstring> ...

  3. 10-18 noip提高组模拟赛(codecomb)T1倍增[未填]

    T1只想到了找环,> <倍增的思想没有学过,所以看题解看得雨里雾里的(最近真的打算学一下! 题目出的挺好的,觉得noip极有可能出现T1T2T3,所以在此mark 刚开始T1以为是模拟,还 ...

  4. 10-18 noip提高组模拟赛(codecomb)T2贪心

    T2:找min:一直找最小的那个,直到a[i]-x+1小于0,就找次小的,以此类推: 求max,也是一样的,一直到最大的那个,直到次大的比之前最大的大,就找次大的: 这个模拟,可以用上priority ...

  5. 【洛谷】NOIP提高组模拟赛Day1【组合数学】【贪心+背包】【网络流判断是否满流以及流量方案】

    U41568 Agent1 题目背景 2018年11月17日,中国香港将会迎来一场XM大战,是世界各地的ENLIGHTENED与RESISTANCE开战的地点,某地 的ENLIGHTENED总部也想派 ...

  6. noip提高组模拟赛(QBXT)T2

    T2count题解 [ 问题描述]: 小 A 是一名热衷于优化各种算法的 OIER,有一天他给了你一个随机生成的 1~n 的排列, 并定 义区间[l,r]的价值为: \[ \huge C_{l,r}= ...

  7. [LUOGU] NOIP提高组模拟赛Day1

    题外话:以Ingress为题材出的比赛好评,绿军好评 T1 考虑枚举第\(i\)个人作为左边必选的一个人,那左边剩余\(i-1\)个人,选法就是\(2^{i-1}\),也就是可以任意选或不选,右侧剩余 ...

  8. 计蒜客 2017 NOIP 提高组模拟赛(四)Day1 T2 小X的密室

    https://nanti.jisuanke.com/t/17323 小 X 正困在一个密室里,他希望尽快逃出密室. 密室中有 N 个房间,初始时,小 X 在 1号房间,而出口在 N号房间. 密室的每 ...

  9. HGOI2010816 (NOIP 提高组模拟赛 day1)

    Day1 210pts(含T1莫名的-10pts和T3莫名的-30pts) 100+70+40=210 rank 29 这道题第一眼看是字符串匹配问题什么KMP啊,又想KMP不会做啊,那就RK Has ...

随机推荐

  1. 你也可以自己写一个可爱 & 小资风格的Android加载等待自定义View - 转

    http://blog.csdn.net/carson_ho/article/details/77712072

  2. VB6 CHECK is run as admin privilege

    vb6 code: Private Declare Function IsUserAnAdmin Lib "Shell32" Alias "#680" () A ...

  3. 20155237方自晨 实验四android开发基础

    提交点一 Android Stuidio的安装测试: 参考<Java和Android开发学习指南(第二版)(EPUBIT,Java for Android 2nd)>第二十四章: 安装 A ...

  4. 20155320《网络对抗》Exp2 后门原理与实践

    20155320<网络对抗>Exp2 后门原理与实践 [实验内容] (3.5分) (1)使用netcat获取主机操作Shell,cron启动 (2)使用socat获取主机操作Shell, ...

  5. POJ 3349&&3274&&2151&&1840&&2002&&2503

    (今天兴致大发学了Markdown,第一篇博客) 这次的主要都是hash的题目(当然这就意味这可以用map) hash的方式也有很多: 普通hash hash挂链 双hash以及自然溢出等 当然我还是 ...

  6. 使用 spring-boot-devtools 进行热部署

    2019/3/5 更新: 发现热部署不生效,出现页面显示error的错误,然后在 application.properties 中注释了下面两行成功实现热部署(直接删掉也可以) #spring.dev ...

  7. Java类加载器学习笔记

    今后一段时间会全面读一下<深入理解Java虚拟机> 在这里先记一下在网上看到的几篇介绍 类加载器 的文章,等读到虚拟机类加载机制再详细介绍. 超详细Java中的ClassLoader详解 ...

  8. 设计模式 笔记 单例模式 Singleton

    //---------------------------15/04/09---------------------------- //Singleton 单例模式-----对象创建型模式 /* 1: ...

  9. flask-login 整合 pyjwt + json 简易flask框架

    现在很多框架都实现前后端分离,主要为了适应以下几个目的: 1,前后端的分离,可以使前端开发和后端开发更加分工明确,而不是后端还需要在视图模板中加入很多{% XXXX %}标签 2,是为了适应跨域调用或 ...

  10. IOS免越狱虚拟定位修改工具共享 Jocation

    Jocation IOS虚拟定位修改器 具体使用方法可以按照 location cleaned软件相同的操作. 主要是因为本人有一部 IphoneX 和Iphone Xs Max 网上的locatio ...