Warsaw University Contest Petrozavodsk, Thursday, January 31, 2008 J题,Gym100096J

本文介绍了一个算法问题,即从给定的2n个整数中找出一个长度为n的子序列,使得其元素之和能被n整除。讨论了通过排序和随机重排策略来高效解决此问题的方法。

Problem J.

Sum of a subsequence Input file: sum.in Output file: sum.out We are given a sequence a1, a2, . . . , a2n. Your task is to find a subsequence ai1 , ai2 , . . . , ain of this sequence such that its sum ai1 + ai2 + · · · + ain is divisible by n, or check that such subsequence doesn’t exist.

Input The first line of the input file contains one integer n (1 ≤ n ≤ 100 000). The second line contains 2n integers ai (1 ≤ ai ≤ 1 000 000 000), separated by single spaces. You can assume that n ∈ {10, 100, 1 000, 10 000, 100 000}.

Output If there is no subsequence that satisfies the described conditions then the first and only line of the output file should contain one word IMPOSSIBLE. Otherwise the first and only line of the output file should contain n integers i1 < i2 < · · · < in, such that n|(ai1 + ai2 + · · · + ain ). In case of multiple correct answers your program should output any one. Example sum.in sum.out 10 17 10 13 15 10 4 14 4 9 5 3 2 1 5 19 12 19 9 17 11 1 3 5 6 12 13 14 16 18 19 The real sample input fits in exactly two lines — the example above is formatted in 3 lines only for technical reasons.

 

题目分析:

这个题十分的优秀

首先考虑序列有序的情况,先领序列对n取余。

比如10w个1,10w个2

那么这种情况排序后,即可解决。

如果排序不能解决,就random_shuffle随机化处理

reorder的每n个数,都有1/n的概率成为答案。reorder后有n个数,那么期望reorder一次就可以找到答案。

 1 #include<bits/stdc++.h>
 2 //#define fi first
 3 //#define se second 
 4 #define Pii pair<int,int> 
 5 #define maxn 400100
 6 using namespace std;
 7 Pii seg[maxn];
 8 int n,sum[maxn],m;
 9 int ans[maxn],cnt=0;
10 inline void Spaly(int &v)
11 {
12     v=0;
13     char c=0;
14     int p=1;
15     while (c<'0' || c>'9') {if (c=='-') p=-1;c=getchar();}
16     while (c>='0' && c<='9') {v=(v<<3)+(v<<1)+c-'0';c=getchar();}
17     v*=p;
18     //v%=n;
19 } 
20 int main(){
21     freopen("sum.in","r",stdin);
22     freopen("sum.out","w",stdout);
23     cin>>n;
24     m=2*n;
25     for(int i=1;i<=2*n;i++){
26     //    Spaly(seg[i].first);
27         scanf("%d",&seg[i].first);
28         //if(seg[i].first>1000000000) while(1);
29     //    seg[i].first%=n; 
30         seg[i].second=i;
31     }
32     sort(seg+1,seg+1+m);
33     bool flag=false;
34     while(true){
35         for(int i=1;i<=m;i++){
36             sum[i]=(sum[i-1]+seg[i].first)%n;
37         }
38         for(int i=n;i<=m;i++){
39             if(sum[i]==sum[i-n]){
40                 flag=true;
41                 for(int j=i-n+1;j<=i;j++){
42                     ans[++cnt]=seg[j].second;
43                 }    
44                 break;
45             }
46         }
47         if(flag) break;
48         random_shuffle(seg+1,seg+1+m);
49     }
50     sort(ans+1,ans+1+n);
51     for(int i=1;i<=n;i++){
52         printf("%d ",ans[i]);
53     }
54     return 0;
55 }

 

转载于:https://www.cnblogs.com/poler/p/7342165.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值