期望得分:100+100+40=240

实际得分:100+40+0=140

T1 一道图论神题(god)

Time Limit:1000ms   Memory Limit:128MB

题目描述

LYK有一张无向图G={V,E},这张无向图有n个点m条边组成。并且这是一张带权图,只有点权。

LYK想把这个图删干净,它的方法是这样的。每次选择一个点,将它删掉,但删这个点是需要代价的。假设与这个点相连的还没被删掉的点是u1,u2,…,uk。LYK将会增加a[u1],a[u2],…,a[uk]的疲劳值。

它想将所有点都删掉,并且删完后自己的疲劳值之和最小。你能帮帮它吗?

输入格式(god.in)

第一行两个数n,m表示一张n个点m条边的图。

第二行n个数ai表示点权。

接下来m行每行三个数u,v,表示有一条连接u,v的边。数据保证任意两个点之间最多一条边相连,并且不存在自环。

输出格式(god.out)

你需要输出这个最小疲劳值是多少。

输入样例

4 3

10 20 30 40

1 4

1 2

2 3

输出样例

40

样例解释

一个合理的方法是先删4号点,此时有10点疲劳值。接下来删3号点,获得20点疲劳值,再删2号点,获得10点疲劳值,最后删1号点,没有疲劳值。总计40点疲劳值。

对于30%的数据n<=10。

对于60%的数据n,m<=1000。

对于100%的数据1<=n,m,ai<=100000

m条边,疲劳值就会计算m次

所以可以贪心的选择 每条边的疲劳值小的点累计

正确性:如果每条无向边改为疲劳值大的点向疲劳值小的点的有向边,那么这张图就是DAG

#include<cstdio>
#include<algorithm>
#define N 100001
using namespace std;
int val[N];
void out(long long x)
{
if(x/) out(x/);
putchar(x%+'');
}
int main()
{
freopen("god.in","r",stdin);
freopen("god.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",&val[i]);
int u,v;
long long ans=;
for(int i=;i<=m;i++)
{
scanf("%d%d",&u,&v);
ans+=min(val[u],val[v]);
}
out(ans);
}

T2 位运算2(bit)

Time Limit:1000ms   Memory Limit:128MB

题目描述

LYK拥有一个十进制的数N。它赋予了N一个新的意义:不考虑N的符号,将N每一位都拆开来后再加起来就是N所拥有的价值。例如数字123拥有6的价值,数字999拥有27的价值,数字-233拥有8的价值。

假设数字N的价值是K,LYK想找到一个价值是K+1的数字,当然这个答案实在太多了,LYK想使得这个价值为K+1的数字尽可能大,并且需要保证这个数字小于N。

输入格式(bit.in)

一个整数N。

输出格式(bit.out)

一个数表示答案。你需要输出一个整数,且这个数不包含前导0。

输入样例1

199

输出样例1

-299

输入样例2

1520

输出样例2

1512

对于20%的数据|N|<=10

对于40%的数据|N|<=100

对于60%的数据|N|<=10^9

对于80%的数据|N|<=10^1000

对于100%的数据|N|<=10^100000。

正数和负数分开讨论

正数:

① 设第i位之后的数位之和为gather,第i位为num,那么如果gather<=(len-i)*9+num-1,

最优解就是第i位为num-1,之后的数贪心填当前能填的最大的,之前就是原数

② 找不到满足条件①的,最优解只能是负数,那就是找绝对值最小的那个

设数位之和为tot,那么第一位为tot%9,后面tot/9个9

负数:

从后往前找到第一个小于9的位置,这个位置的数+1,其余位置的数不变

考场上忘了判断负数,WA了5个点

正数的情况①中,没有判断第i位可能是要输出的第一位,且num-1=0,WA了1个点

#include<cstdio>
#include<cstring>
using namespace std;
char s[];
int num[],tot,gather;
int main()
{
freopen("bit.in","r",stdin);
freopen("bit.out","w",stdout);
scanf("%s",s);
int len=strlen(s);
if(s[]!='-')
{
for(int i=;i<len;i++) num[i]=s[i]-'',tot+=num[i];
gather=num[len-]+;
for(int i=len-;i>=;i--)
{
gather+=num[i];
if(!num[i]) continue;
if((len-i-)*+num[i]->=gather)
{
bool ok=false;
for(int j=;j<i;j++) ok=true,printf("%d",num[j]);
if(ok || num[i]>) printf("%d",num[i]-);
gather-=(num[i]-);
for(int j=i+;j<len;j++)
if(gather>=) printf(""),gather-=;
else printf("%d",gather),gather=;
return ;
}
}
putchar('-');
tot++;
int n=tot/;
if(tot%) printf("%d",tot%);
for(int i=;i<=n;i++) printf("");
return ;
}
else
{
putchar('-');
for(int i=;i<len;i++) num[i]=s[i]-'';
for(int i=len-;i;i--)
if(num[i]<)
{
for(int j=;j<i;j++) printf("%d",num[j]);
printf("%d",num[i]+);
for(int j=i+;j<len;j++) printf("%d",num[j]);
return ;
}
printf("");
for(int i=;i<len;i++) printf("%d",num[i]);
return ;
}
}

T3 逆序对(pair)

Time Limit:1000ms   Memory Limit:128MB

题目描述

LYK最近在研究逆序对。

这个问题是这样的。

一开始LYK有一个2^n长度的数组ai。

LYK有Q次操作,每次操作都有一个参数k。表示每连续2^k长度作为一个小组。假设n=4,k=2,则a[1],a[2],a[3],a[4]为一个小组,a[5],a[6],a[7],a[8]为一个小组,a[9],a[10],a[11],a[12]为一个小组,a[13],a[14],a[15],a[16]也为一个小组。

然后LYK对于每个小组都翻转,也就是说原数组会变成a[4],a[3],a[2],a[1],a[8],a[7],a[6],a[5],a[12],a[11],a[10],a[9],a[16],a[15],a[14],a[13]。之后它想求出这2^n个数的逆序对是多少。

因此你需要输出对于每次操作,操作完后这2^n个数的逆序对有多少对。

两个数ai,aj被称为逆序对当且仅当i<j且ai>aj。

输入格式(pair.in)

第一行一个数n。

接下来一行2^n个数ai表示一开始的数组。

接下来一行一个数Q,表示操作的次数。

接下来一行Q个数,表示每次操作的参数k。

输出格式(pair.out)

Q行,表示每次操作后的答案。

输入样例

2

2 1 4 3

4

1 2 0 2

输出样例

0

6

6

0

样例解释

第一次操作,{2,1,4,3}->{1,2,3,4}

第二次操作,{1,2,3,4}->{4,3,2,1}

第三次操作,{4,3,2,1}->{4,3,2,1}

第四次操作,{4,3,2,1}->{1,2,3,4}

对于30%的数据n<=10,Q<=10。

对于50%的数据n<=10,Q<=1000。

对于80%的数据n<=10,Q<=200000。

对于100%的数据n<=17,Q<=200000,1<=ai<=2^n。

例:1 2 3 4 5 6 7 8  k=3

翻转结果为 8 7 6 5 4 3 2 1

将翻转过程拆分:

第一步: 2 1 4 3 6 5 8 7

第二步:4 3 2 1 8 7 6 5

第三步:8 7 6 5 4 3 2 1

所以每一次翻转都可以拆分,而拆分的过程就是交换相邻的2^(步数-1)

所以归并排序求逆序对的时候,用st表维护从第i个位置,长为2^j的区间的逆序对个数

然后求出对应区间的顺序对个数

维护所有长为2^i的区间的逆序对个数rev[i]和顺序对个数pos[i]

统计答案的时候,拆分就是swap(rev,pos)

在这里顺序对个数是用总个数-逆序对个数求的

所以就会有一个问题,例:

2 2 3 3

实际上的:

pos : 0  0

rev :  0  0

但求的时候,pos :2  4

因为用总个数-逆序对个数=顺序对个数+相等的数对

所以归并过程中,还要预处理从第i个位置,长为2^j的区间的相等数对个数

计算rev,pos时,同时计算same[i],表示所有长为2^i的区间相等的数对个数

求解的时候 先swap(rev,pos),然后rev-=same,再 pos=总的-rev

#include<cstdio>
#include<iostream>
#include<algorithm> #define N 17
//#define M 1<<N using namespace std; typedef long long LL; const int M=<<; int n,tot;
int a[M+],res[M+],bit[M+],P[M+];
LL st[M+][N+],ST[M+][N+];
LL rev[N+],pos[N+],same[N+],sum[N+]; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} void gbsort(int l,int r)
{
if(l==r) return;
int mid=l+r>>;
gbsort(l,mid);
gbsort(mid+,r);
for(int p=r;p>=l;--p) P[p]=p;
for(int p=r-;p>=l;--p)
if(a[p]==a[p+]) P[p]=P[p+];
int i=l,j=mid+,k=l;
while(i<=mid && j<=r)
{
if(a[i]>a[j]) st[l][bit[r-l+]]+=mid-i+,res[k++]=a[j++];
else if(a[i]==a[j]) ST[l][bit[r-l+]]+=P[j]-j+,res[k++]=a[i++];
else res[k++]=a[i++];
}
while(i<=mid) res[k++]=a[i++];
while(j<=r) res[k++]=a[j++];
for(k=l;k<=r;++k) a[k]=res[k];
} void pre()
{
for(int i=;i<=n;++i) sum[i]=1ll*(<<i-)*(<<i-);
for(int i=,len=;i<=n;++i,len<<=)
for(int j=;j<=tot;j+=len)
rev[i]+=st[j][i],pos[i]+=sum[i]-st[j][i],same[i]+=ST[j][i];
} int main()
{
freopen("pair.in","r",stdin);
freopen("pair.out","w",stdout);
read(n); tot=<<n;
for(int i=;i<=tot;++i) bit[i]=bit[i>>]+;
for(int i=;i<=tot;++i) read(a[i]);
gbsort(,tot);
pre();
int m,k; read(m);
LL ans;
while(m--)
{
read(k);ans=;
for(int i=;i<=k;++i) swap(rev[i],pos[i]),rev[i]-=same[i],pos[i]=sum[i]*tot/(<<i)-rev[i];
for(int i=;i<=n;++i) ans+=rev[i];
printf("%I64d\n",ans);
}
return ;
}

考场上40分暴力也打炸了

1、归并排序最后没有for(k=l;k<=r;k++) a[k]=res[k];

2、归并排序后数组变为有序,下一次操作前没有还原

3、输入n,元素有1<<n个,全用的n

暴力:

#include<cstdio>
#include<iostream>
#define N 131073
using namespace std;
typedef long long LL;
int a[N],tot,res[N],t[N];
LL ans;
inline void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
}
void reverse(int k)
{
int len=<<k,tmp=len>>;
for(int i=;i<=tot;i+=len)
{
for(int j=;j<=tmp;j++)
swap(a[j+i-],a[len-j++i-]);
}
}
void gbsort(int l,int r)
{
if(l==r) return;
int mid=l+r>>;
gbsort(l,mid);
gbsort(mid+,r);
int i=l,j=mid+,k=l;
while(i<=mid && j<=r)
{
if(a[i]>a[j]) { ans+=mid-i+; res[k++]=a[j++]; }
else res[k++]=a[i++];
}
while(i<=mid) res[k++]=a[i++];
while(j<=r) res[k++]=a[j++];
for(k=l;k<=r;k++) a[k]=res[k];
}
void out(long long x)
{
if(x/) out(x/);
putchar(x%+'');
}
int main()
{
freopen("pair.in","r",stdin);
freopen("pair.out","w",stdout);
int n; read(n);
tot=<<n;
for(int i=;i<=tot;i++) read(a[i]);
int q,k;
read(q);
while(q--)
{
read(k);
reverse(k);
for(int i=;i<=tot;i++) t[i]=a[i];
ans=;
gbsort(,tot);
for(int i=;i<=tot;i++) a[i]=t[i];
out(ans);
printf("\n");
}
fclose(stdin); fclose(stdout);
return ;
}

2017北京国庆刷题Day2 morning的更多相关文章

  1. 2017北京国庆刷题Day2 afternoon

    期望得分:100+100+50=250 实际得分:100+70+50=220 T1 最大值(max) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有一 ...

  2. 2017北京国庆刷题Day1 afternoon

    期望得分:100+100+100=300 实际得分:100+100+100=300 T1 一道图论好题(graph) Time Limit:1000ms   Memory Limit:128MB 题目 ...

  3. 2017北京国庆刷题Day7 morning

    期望得分:100+0+100=200 实际得分:100+20+0=120 离散化搞搞 #include<cstdio> #include<iostream> #include& ...

  4. 2017北京国庆刷题Day5 afternoon

    期望得分:100+60+100=260 实际得分:0+60+40=100 设图中有m个环,每个环有si条边,有k条边不在环中 ans= (2^s1 -2)*( 2^s2 -2)* (2^s3 -2)… ...

  5. 2017北京国庆刷题Day3 morning

    期望得分:100+60+0=160 实际得分:100+30+0=130 考场上用的哈希 #include<cstdio> #include<cstring> #include& ...

  6. 2017北京国庆刷题Day4 morning

    期望得分:0+40+30=70 实际得分:0+10+10=20 题目修改:只能由0变1,只能用一次操作 大模拟 #include<cstdio> #include<cstring&g ...

  7. 2017北京国庆刷题Day5 morning

    期望得分:0+60+60=120 实际得分:0+30+60=90 令g=gcd(X11,X12,X13……) 则行列式可能为D的充要条件为g|D 1.g|D为必要条件: 由定义来算行列式的时候,每一项 ...

  8. 2017北京国庆刷题Day4 afternoon

    期望得分:100+100+0=200 实际得分:5+0+0=5 每加入一个数,x的因数位置++ 注意:根号x枚举时,如果x是完全平方数,根号x会重复累计2次,要减去 考场上没减,5分 /(ㄒoㄒ)/~ ...

  9. 2017北京国庆刷题Day6 afternoon

    期望得分:100+100+40=240 实际得分:100+0+40=140 二进制拆分.二进制前缀和 #include<cstdio> #include<iostream> u ...

随机推荐

  1. JAVA方法的重载(overload)和覆盖(override)

    方法的重载(overload)和覆盖(override) 有的时候,类的同一种功能有多种实现方式,到底采用哪种实现方式,取决于调用者给定的参数.例如我们最常用的System.out.println() ...

  2. PAT 甲级 1083 List Grades

    https://pintia.cn/problem-sets/994805342720868352/problems/994805383929905152 Given a list of N stud ...

  3. (十三)Jmeter之Bean Shell 的使用(二)

    该文章来自:http://www.cnblogs.com/puresoul/p/5092628.html 上一篇Jmeter之Bean shell使用(一)简单介绍了下Jmeter中的Bean she ...

  4. 模板CodeTemplate

    /** * @author:dubbo@xxxx.com * @date: ${date} ${time} * @version: V1.0 * @review: dubbo/${date} ${ti ...

  5. 从理论到实践,全方位认识DNS

    从理论到实践,全方位认识DNS 2015-11-23 程序员之家 作者:selfboot 原文:http://segmentfault.com/a/1190000003956853 对于 DNS(Do ...

  6. [学习]WireShark 的过滤功能

    1. 打开 wireShark 过滤显示 协议 比如显示arp协议 过滤栏输入arp即可 支持的协议类型 TCP UDP HTTP FTP ICMP SMTP等等 2. 过滤ip地址 ip.addr ...

  7. SharePoint 2016 Document Center Send To Connection

    General Application setting->configure send to connection then i had to choose web application&qu ...

  8. perf的统计模式: 突破口: x86_perf_event_update

    之前一直以为perf的统计模式也是通过中断出发来的,于是会在中断处理函数中做处理,但是如果perf是统计模式,那么perf的寄存器就不会是溢出的模式了,这个时候,就没有pmu的中断发生,所以很奇怪呢, ...

  9. Java多线程 -sleep 用法详解

    阿里面试官问我这个问题,我仔细总结了一下: 参考:sleep.yield.wait.join的区别(阿里面试) 我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确 ...

  10. oracle 数据库 命令

    SQL PLUS 命令: SELECT * FROM ALL_TABLES;系统里有权限的表SELECT * FROM DBA_TABLES; 系统表SELECT * FROM USER_TABLES ...