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
1 /* 2 对于一条边的两个端点,肯定是选权值大最优 3 然后对于每条边,都采取这种策略就完成了 4 */ 5 #include <algorithm> 6 #include <cstdio> 7 8 inline void read(int &x) 9 { 10 x=0; register char ch=getchar(); 11 for(; ch>'9'||ch<'0'; ) ch=getchar(); 12 for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 13 } 14 const int N(100005); 15 int n,m,val[N]; 16 long long ans; 17 18 int Presist() 19 { 20 freopen("god.in","r",stdin); 21 freopen("god.out","w",stdout); 22 read(n),read(m); 23 for(int i=1; i<=n; ++i) read(val[i]); 24 for(int u,v,i=1; i<=m; ++i) 25 { 26 read(u),read(v); 27 ans+=(long long)std::min(val[u],val[v]); 28 } 29 printf("%I64d",ans); 30 return 0; 31 } 32 33 int Aptal=Presist(); 34 int main(int argc,char**){;}
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。
对于负数的情况从后往前找第一个不是9的数++
1 #include <cstring> 2 #include <cstdio> 3 4 inline void read(int &x) 5 { 6 x=0; register char ch=getchar(); 7 for(; ch>'9'||ch<'0'; ) ch=getchar(); 8 for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 9 } 10 char s[100005]; 11 int n,num[100005]; 12 13 inline void work1() 14 { 15 int i,flag=0; 16 for(i=2; i<=n; ++i) num[i]=s[i]-'0'; 17 for(i=n; i>1; --i) 18 if(num[i]!=9) 19 { 20 num[i]++; 21 flag=1; 22 break; 23 } 24 printf("-"); 25 if(!flag) printf("1"); 26 for(int i=2; i<=n; ++i) printf("%d",num[i]); 27 } 28 29 int K; 30 inline void work2() 31 { 32 for(int i=1; i<=n; ++i) num[i]=s[i]-'0',K+=num[i]; 33 if(num[1]==1&&num[2]==0&&n==2) { printf("%d ",2); return ; } 34 if(++K<10&&n==2&&num[1]==1) { printf("%d ",K); return ; } 35 } 36 37 int Presist() 38 { 39 // freopen("bit.in","r",stdin); 40 // freopen("bit.out","w",stdout); 41 scanf("%s",s+1);n=strlen(s+1); 42 if(s[1]=='-') work1(); 43 else work2(); 44 return 0; 45 } 46 47 int Aptal=Presist(); 48 int main(int argc,char**){;}
对于正数的情况,
①设当前位置i到最后一位的价值为tot,如果tot<=(n-i)*9+num[i]-1
最优解为1~i-1为原数,i+1~n尽量填最大,num[i]--;
②否则,为绝对数值最小的负数,等价于位数最小的负数,第一位之后填尽量多的9
1 #include <cstring> 2 #include <cstdio> 3 4 inline void read(int &x) 5 { 6 x=0; register char ch=getchar(); 7 for(; ch>'9'||ch<'0'; ) ch=getchar(); 8 for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 9 } 10 const int N(100005); 11 int n,num[N],k[N],K; 12 char s[N]; 13 14 inline void work1() 15 { 16 int i,flag=0; 17 for(i=2; i<=n; ++i) num[i]=s[i]-'0'; 18 for(i=n; i>1; --i) 19 if(num[i]!=9) 20 { 21 num[i]++; 22 flag=1; 23 break; 24 } 25 printf("-"); 26 if(!flag) printf("1"); 27 for(int i=2; i<=n; ++i) printf("%d",num[i]); 28 } 29 30 inline void work2() 31 { 32 for(int i=1; i<=n; ++i) num[i]=s[i]-'0',K+=num[i]; 33 int tot=num[n]+1; 34 for(int i=n-1; i>=1; --i) 35 { 36 tot+=num[i]; 37 if(!num[i]) continue; 38 if(tot<=num[i]-1+(n-i)*9) 39 { 40 num[i]--;tot-=num[i]; 41 if(num[1]) printf("%d",num[1]); 42 for(int j=2; j<=i; ++j) printf("%d",num[j]); 43 for(int j=i+1; j<=n; ++j) 44 if(tot>=9) printf("9"),tot-=9; 45 else printf("%d",tot),tot=0; 46 return ; 47 } 48 } 49 printf("-"); K++; int len=K/9; 50 if(K%9) printf("%d",K%9); 51 for(; len--; ) printf("9"); 52 } 53 54 int Presist() 55 { 56 // freopen("bit.in","r",stdin); 57 // freopen("bit.out","w",stdout); 58 scanf("%s",s+1);n=strlen(s+1); 59 if(s[1]=='-') work1(); 60 else work2(); 61 return 0; 62 } 63 64 int Aptal=Presist(); 65 int main(int argc,char**){;}
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。
归并排序求逆序对的时候,用st表维护从第i个位置,长为2^j的区间的逆序对个数
然后求出对应区间的顺序对个数
维护所有长为2^i的区间的逆序对个数rev[i]和顺序对个数seq[i]
统计答案的时候,拆分就是swap(rev,seq)
在这里顺序对个数是用总个数-逆序对个数求的,要注意相等的情况
因为用总个数-逆序对个数=顺序对个数+相等的数对
所以归并过程中,还要预处理从第i个位置,长为2^j的区间的相等数对个数
计算rev,seq时,同时计算same[i],表示所有长为2^i的区间相等的数对个数
求解的时候 先swap(rev,seq),然后rev-=same,再seq=总的-rev
1 #include <cstdio> 2 3 #define LL long long 4 #define swap(a,b) {LL c=a;a=b;b=c;} 5 6 inline void read(int &x) 7 { 8 x=0; register char ch=getchar(); 9 for(; ch>'9'||ch<'0'; ) ch=getchar(); 10 for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 11 } 12 const int N(1<<17); 13 int n,nn,m,a[N+5],log2[N+5]; 14 15 int last[N+5],order[N+5]; 16 LL st[N+5][18],euq[N+5][18]; 17 LL same[N+5],seq[N+5],rev[N+5],sum[N+5]; 18 void Merge_sort(int l,int r) 19 { 20 if(l==r) return ; 21 int mid=l+r>>1; 22 Merge_sort(l,mid); 23 Merge_sort(mid+1,r); 24 int i,j,k,len=log2[r-l+1]; 25 for(i=l; i<=r; ++i) last[i]=i; 26 for(i=r; i>l; --i) 27 if(a[i]==a[i-1]) last[i-1]=last[i]; 28 for(i=k=l,j=mid+1; i<=mid&&j<=r; ) 29 if(a[i]==a[j]) euq[l][len]+=last[j]-j+1,order[k++]=a[i++]; 30 else if(a[i]>a[j]) st[l][len]+=mid-i+1,order[k++]=a[j++]; 31 else order[k++]=a[i++]; 32 for(; i<=mid; ) order[k++]=a[i++]; 33 for(; j<=r; ) order[k++]=a[j++]; 34 for(i=l; i<=r; ++i) a[i]=order[i]; 35 } 36 37 inline void Prepare() 38 { 39 for(int i=2; i<=nn; ++i) log2[i]=log2[i>>1]+1; 40 Merge_sort(1,nn); 41 for(int i=1; i<=n; ++i) sum[i]=1ll*(1<<i-1)*(1<<i-1); 42 for(int len=2,i=1; i<=n; ++i,len<<=1) 43 for(int j=1; j<=nn; j+=len) 44 { 45 rev[i]+=st[j][i], 46 same[i]+=euq[j][i], 47 seq[i]+=sum[i]-st[j][i]; 48 } 49 } 50 51 int Presist() 52 { 53 // freopen("pair.in","r",stdin); 54 // freopen("pair.out","w",stdout); 55 read(n),nn=1<<n; 56 for(int i=1; i<=nn; ++i) read(a[i]); 57 Prepare(),read(m); 58 for(int k; m--; ) 59 { 60 read(k);long long ans=0; 61 for(int i=1; i<=k; ++i) 62 { 63 swap(rev[i],seq[i]); 64 rev[i]-=same[i]; 65 seq[i]=sum[i]*nn/(1<<i)-rev[i]; 66 } 67 for(int i=1; i<=n; ++i) ans+=rev[i]; 68 printf("%I64d ",ans); 69 } 70 return 0; 71 } 72 73 int Aptal=Presist(); 74 int main(int argc,char**argv){;}