一道图论神题(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

思路:贪心,一遍AC。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define MAXN 101000
using namespace std;
map<int,int>ma[MAXN];
int n,m,tot,cap[MAXN];
long long ans;
int to[MAXN*],net[MAXN*],head[MAXN*];
struct nond{
int val,id;
}v[MAXN];
int cmp(nond a,nond b){
return a.val>b.val;
}
void add(int u,int v){
to[++tot]=v;net[tot]=head[u];head[u]=tot;
to[++tot]=u;net[tot]=head[v];head[v]=tot;
}
int main(){
freopen("god.in","r",stdin);
freopen("god.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
scanf("%d",&v[i].val);
v[i].id=i;
cap[i]=v[i].val;
}
sort(v+,v++n,cmp);
for(int i=;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
ma[u][v]=;
ma[v][u]=;
}
for(int i=;i<=n;i++){
for(int j=head[v[i].id];j;j=net[j])
if(ma[v[i].id].find(to[j])!=ma[v[i].id].end()){
ans+=cap[to[j]];
ma[to[j]].erase(v[i].id);
}
}
cout<<ans;
}
/*
4 3
10 20 30 40
1 4
1 2
2 3
*/

位运算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。

思路:大模拟,有三种情况没有考虑,挂掉了3个点。

~~~~(>_<)~~~~ 改不过来了90分代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char n[];
int len;
int num[],tmp[],ans[];
int main(){
freopen("bit.in","r",stdin);
freopen("bit.out","w",stdout);
int cnt=,flag=,flag1=;
scanf("%s",n);
len=strlen(n);
if(n[]!='-'){
for(int i=;i<len;i++){
num[i+]=n[i]-'';
tmp[i+]=num[i+];
}
if(len!=){
if(num[len]<=&&num[len-]>=){
int y=;
num[len-]-=;num[len]+=;
while(num[y]==) y++;
for(int i=y;i<=len;i++) cout<<num[i];
return ;
}
else if(num[len]>&&num[len-]>=){
if(num[len-]!=){
int bns=-num[len-]-,y=;
num[len-]-=;
num[len-]=;
num[len]-=bns;
while(num[y]==) y++;
for(int i=y;i<=len;i++) ans[++cnt]=num[i];
}
else{
int x=,y=;
int bns=-num[len-]-;
while(!num[len-x]&&len!=) x++;
num[len-x]-=;
num[len-x+]=;
num[len-x+]=num[len]-bns;
while(num[y]==) y++;
for(int i=y;i<=len-x+;i++) ans[++cnt]=num[i];
for(int i=len-x+;i<=len;i++) ans[++cnt]=;
}
for(int i=;i<=cnt;i++)
if(ans[i]>=||ans[i]<) flag=;
if(len==cnt)
for(int i=;i<=cnt;i++)
if(ans[i]>tmp[i]){
flag=;
break;
}
else if(ans[i]<tmp[i])
break;
if(flag){
cout<<"-";
for(int i=len;i>=;i--)
if(tmp[i]!=){
flag1=;
tmp[i]+=;
break;
}
if(!flag1) tmp[]+=;
}
if(!flag) for(int i=;i<=len;i++) cout<<ans[i];
if(flag&&flag1) for(int i=;i<=len;i++) cout<<tmp[i];
else if(flag&&!flag) for(int i=;i<=len;i++) cout<<tmp[i];
return ;
}
else if(num[len]<=&&num[len-]<){
int x=,y=;
while(!num[len-x]) x++;
num[len-x]-=;
num[len-x+]=num[len]+;
while(num[y]==) y++;
for(int i=;i<=len-x+;i++) cout<<num[i];
for(int i=len-x+;i<=len;i++) cout<<"";
return ;
}
}
else{
cout<<"-"<<num[]+;
return ;
}
}
else{
len-=;
for(int i=;i<=len;i++){
num[i]=n[i]-'';
tmp[i]=num[i];
}
for(int i=len;i>=;i--)
if(tmp[i]!=){
flag1=;
tmp[i]+=;
break;
}
if(!flag1) tmp[]+=;
cout<<"-";
if(flag1) for(int i=;i<=len;i++) cout<<tmp[i];
else for(int i=;i<=len;i++) cout<<tmp[i];
return ;
}
}

这是标程:

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
char s[];
int len,sum,i,j,FLAG;
int main()
{
freopen("bit.in","r",stdin);
freopen("bit.out","w",stdout);
scanf("%s",s); FLAG=;
if (s[]!='-')
{
len=strlen(s); sum=;
for (i=len-; i>=; i--)
{
if (s[i]>='' && sum>=)
{
s[i]=char(s[i]-);
sum=;
for (j=i+; j<len; j++)
{
while (sum && s[j]<'')
{
sum--;
s[j]=char(s[j]+);
}
}
int SS=;
for (j=i+; j<len; j++) SS+=s[j]-'';
for (j=i+; j<len; j++)
{
if (SS>=) {s[j]=''; SS-=;} else {s[j]=char(SS+''); SS=;}
}
FLAG=;
break;
}
sum+=''-s[i];
}
if (FLAG)
{
for (i=; i<len; i++) if (s[i]!='') break;
for (j=min(len-,i); j<len; j++) cout<<s[j]; cout<<endl;
return ;
}
cout<<'-';
for (i=len-; i>=; i--)
{
if (s[i]<'')
{
s[i]=char(s[i]+);
FLAG=;
break;
}
}
if (FLAG)
{
for (i=; i<len; i++) if (s[i]!='') break;
for (j=min(len-,i); j<len; j++) cout<<s[j]; cout<<endl;
return ;
}
cout<<;
for (i=; i<len; i++) if (s[i]!='') break;
for (j=min(len-,i); j<len; j++) cout<<s[j]; cout<<endl;
return ;
} FLAG=;
cout<<'-';
len=strlen(s);
for (i=len-; i>=; i--)
{
if (s[i]<'')
{
s[i]=char(s[i]+);
FLAG=;
break;
}
}
if (FLAG)
{
for (i=; i<len; i++) if (s[i]!='') break;
for (j=min(len-,i); j<len; j++) cout<<s[j]; cout<<endl;
return ;
}
cout<<;
for (i=; i<len; i++) if (s[i]!='') break;
for (j=min(len-,i); j<len; j++) cout<<s[j]; cout<<endl;
return ;
}

逆序对(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<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=(<<)+;
int n,T,PP,now,A,sum,o;
int p[N],a[N],b[N],RR[N];
long long t[],TT[];
long long st[N][],ST[N][];
void pre(int l,int r){
if(l==r) return;
int mid=(l+r)/;
pre(l,mid);
pre(mid+,r);
int i=l,j=mid+,o=l;
for(i=l;i<=r;i++) b[i]=a[i];
for(i=r;i>=mid;i--){
RR[i]=i;
if(i!=r&&b[i+]==b[i])
RR[i]=RR[i+];
}
i=l;j=mid+;
while(i<=mid&&j<=r){
if(b[i]<=b[j]){
a[o++]=b[i];
if(b[i]==b[j])
ST[l][p[r-l+]]+=RR[j]-j+;
i++;
}
else{
a[o++]=b[j];
st[l][p[r-l+]]+=mid-i+;
j++;
}
}
if(i<=mid)
for(j=i;j<=mid;j++) a[o++]=b[j];
else if(j<=r)
for(i=j;i<=r;i++) a[o++]=b[i];
}
int main(){
freopen("pair.in","r",stdin);
freopen("pair.out","w",stdout);
scanf("%d",&n);
sum=(<<n);
for(int i=;i<=sum;i++) scanf("%d",&a[i]);
for(int i=;i<=;i++) p[<<i]=i;
pre(,sum);
for(int i=;i<=n;i++)
for(int j=;j<=(<<n);j+=(<<i)){
t[i]+=st[j][i];
TT[i]+=ST[j][i];
}
scanf("%d",&T);
while(T--){
long long ans=;int Q;
scanf("%d",&Q);
for(int i=;i<=Q;i++) t[i]=1ll*(<<i-)*(<<i-)*(<<n-i)-TT[i]-t[i];
for(int i=;i<=n;i++) ans+=t[i];
printf("%I64d\n",ans);
}
return ;
}

国庆 day 2 上午的更多相关文章

  1. 国庆 day 7 上午

    思路:模拟,set记录一下. #include<set> #include<cstdio> #include<cstring> #include<iostre ...

  2. 国庆 day 3 上午

    a[问题描述] 你是能看到第一题的 friends 呢. ——hja 怎么快速记单词呢?也许把单词分类再记单词是个不错的选择.何大爷给 出了一种分单词的方法,何大爷认为两个单词是同一类的当这两个单词的 ...

  3. 国庆 day 6 上午

    1. 角谷猜想(kakutani.pas/c/cpp)(kakutani.in/out)时间限制:1s/空间限制:256M[题目描述] 某个名字末尾是 654321 的小 A 同学是个大家眼中公认的学 ...

  4. 2018国庆YALI集训游记

    想了想,像之前那样简略地叙述题意和做法,根本没讲清楚,没有任何意义,还不如写写自己的感受. 感觉YALI真的是一所挺不错的学校吧.总是能有一机房的julao轮番吊打你,总是能有集训队的奆佬来给你出dl ...

  5. SSH-Struts第三弹:传智播客视频教程第一天上午的笔记

    一. 框架概述1.三大框架 : 是企业主流 JavaEE 开发的一套架构 Struts2 + Spring + Hibernate 2. 什么是框架?为什么要学框架 ?框架 是 实现部分功能的代码 ( ...

  6. JAVA判断当前时间是上午am还是下午pm

    //结果为"0"是上午 结果为"1"是下午 public class GregorianTest { public static void main(Strin ...

  7. PKUSC 模拟赛 day2 上午总结

    今天上午考得不是很好,主要还是自己太弱QAQ 开场第一题给的图和题意不符,搞了半天才知道原来是走日字形的 然后BFS即可 #include<cstdio> #include<cstr ...

  8. PKUSC 模拟赛 day1 上午总结

    思考了一下第二题,觉得有无数种乱搞做法 类似什么bitset压位,MCS染色之类奇怪的做法 然而都是玄学正确性或者玄学复杂度 先放题解把 第一题显然具有单调性,二分就可以啦 O(nlogn),貌似输出 ...

  9. hihoCoder 1041 国庆出游 (DFS)

    题意: 小Hi和小Ho准备国庆期间去A国旅游.A国的城际交通比较有特色:它共有n座城市(编号1-n):城市之间恰好有n-1条公路相连,形成一个树形公路网.小Hi计划从A国首都(1号城市)出发,自驾遍历 ...

随机推荐

  1. HDU 1558 Segment set( 判断线段相交 + 并查集 )

    链接:传送门 题意:输入一个数 n 代表有 n 组操作,P 是在平面内加入一条线段,Q x 是查询第 x 条线段所在相交集合的线段个数 例如:下图 5 与 1.2 相交,1 与 3 相交,2 与 4 ...

  2. Python 绘图与可视化 matplotlib 填充fill和fill_between

    参考链接:https://blog.csdn.net/You_are_my_dream/article/details/53457960 fill()填充函数曲线与坐标轴之间的区域: x = np.l ...

  3. [luogu] P4040 [AHOI2014/JSOI2014]宅男计划(贪心)

    P4040 [AHOI2014/JSOI2014]宅男计划 题目背景 自从迷上了拼图,JYY就变成了个彻底的宅男.为了解决温饱问题,JYY不得不依靠叫外卖来维持生计. 题目描述 外卖店一共有N种食物, ...

  4. 15 个经常使用的 SQL Server 高级语法

    1.case-end (详细的值) case后面有值,相当于c#中的switch case 注意:case后必须有条件,而且when后面必须是值不能为条件. -----------------case ...

  5. XML 解析---dom解析和sax解析

    眼下XML解析的方法主要用两种: 1.dom解析:(Document Object Model.即文档对象模型)是W3C组织推荐的解析XML的一种方式. 使用dom解析XML文档,该解析器会先把XML ...

  6. leetCode 72.Edit Distance (编辑距离) 解题思路和方法

    Edit Distance Given two words word1 and word2, find the minimum number of steps required to convert  ...

  7. IOS7 textkit 的相关

    去年基于5.0开发的时候.自己用coreText编写了一个富文本,全部的效果都实现的非常好.可是没有去測试效率.只是在cell重用的时候表现不错.在4s上面也不会卡顿. 唯一一个问题就是,在使用AL的 ...

  8. ubuntu中taglist和ctags安装,简单明了

    1.使用命令安装ctags: sudo apt-get install ctags 2.安装taglist 下载: http://vim.sourceforge.net/scripts/downloa ...

  9. AspNet WebApi 中应用fo-dicom抛出异常:No codec registered for tranfer syntax:

    背景: 在做一个Dicom Web Service, 当中WADO-RS中须要解析TransferSyntax, 然后就用到了fo-dicom中的DicomFile.ChangeTransferSyn ...

  10. NOIP2017提高组模拟赛4 (总结)

    NOIP2017提高组模拟赛4 (总结) 第一题 约数 设K是一个正整数,设X是K的约数,且X不等于1也不等于K. 加了X后,K的值就变大了,你可以重复上面的步骤.例如K= 4,我们可以用上面的规则产 ...