昨天考试考得有点迷???
一看内存限制,T1 64MB T2 16MB 当场懵比.........
T1 set
考场打的背包问题和随机化,其实能randA掉,但不小心数组开小了????(长记性!!!!!)
正解的话因为每个前缀只需mod%n,所以有n+1个数,其中一定有重复的
所以就可以O(n)扫了
其实正解不难就是没有细想

1 #include<bits/stdc++.h> 2 #define MAXN 1100 3 using namespace std; 4 int read(){ 5 int x=0;char c=getchar(); 6 while(c<'0'||c>'9')c=getchar(); 7 while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();} 8 return x; 9 } 10 int n; 11 int a[MAXN*MAXN]; 12 struct node{int id,w;}e[1000001]; 13 int ans[MAXN]; 14 int pre[MAXN][1001]; 15 bool biao[2][MAXN]; 16 void work(){ 17 for(int i=1;i<=n;++i){ 18 e[i].id=i;e[i].w=a[i]; 19 } 20 for(int i=1;i<=20000;++i){ 21 if(clock()>990000){ 22 printf("-1 "); 23 return ; 24 } 25 random_shuffle(e+1,e+n+1); 26 int ok=0;int me=0; 27 for(int j=1;j<=n;++j){ 28 me=(me+(e[j].w%n))%n; 29 if(me==0){ 30 ok=j;break; 31 } 32 } 33 if(ok==0)continue; 34 printf("%d ",ok); 35 for(int j=1;j<=ok;++j)printf("%d ",e[j].id); 36 return ; 37 } 38 } 39 signed main(){ 40 n=read(); 41 for(int i=1;i<=n;++i){ 42 a[i]=read();a[i]%=n; 43 } 44 if(n>1000){ 45 work(); 46 return 0; 47 } 48 int now=1;int last=0; 49 biao[last][0]=1; 50 for(int i=1;i<=n;++i){ 51 for(int j=0;j<n;++j){ 52 if(biao[last][j]){ 53 biao[now][j]=1; 54 pre[i][j]=0; 55 } 56 if(biao[last][j]){ 57 biao[now][(j+a[i])%n]=1; 58 pre[i][(j+a[i])%n]=i; 59 } 60 } 61 swap(now,last); 62 memset(biao[now],0,sizeof(biao[now])); 63 } 64 swap(now,last); 65 if(biao[now][0]==0){printf("-1 ");return 0;} 66 now=0; 67 for(int i=n;i>=1;--i){ 68 if(pre[i][now]!=0)ans[++ans[0]]=pre[i][now]; 69 now=(now-a[pre[i][now]]%n+n)%n; 70 } 71 if(ans[0]==0){printf("-1 ");return 0;} 72 printf("%d ",ans[0]); 73 for(int i=1;i<=ans[0];++i){ 74 printf("%d ",ans[i]); 75 } 76 cout<<endl; 77 } 78 /* 79 g++ pai.cpp -o pai 80 ./pai 81 g++ a.cpp -o a 82 ./a 83 */

1 #include<bits/stdc++.h> 2 #define MAXN 1100000 3 #define int long long 4 using namespace std; 5 int vis[MAXN];int n,a[MAXN]; 6 signed main(){ 7 scanf("%lld",&n); 8 vis[0]=0; 9 for(int i=1;i<=n;++i){ 10 scanf("%lld",&a[i]); 11 }int sum=0; 12 for(int i=1;i<=n;++i){ 13 sum=(a[i]+sum)%n; 14 if(vis[sum]!=0){ 15 printf("%lld ",i-vis[sum]); 16 for(int j=vis[sum]+1;j<=i;++j){ 17 printf("%lld ",j); 18 } 19 return 0; 20 } 21 vis[sum]=i; 22 } 23 }
T2 read
考场时看出了答案其实就是2*maxn_sum-N-1,至于证明,除非最后时只剩一种类型的书了,不然肯定能接着放
那么我们就可以直接判断了
考场没算清内存其实1e6的数据是可以开数组的
对于正解,定义一个id,cnt
我们对于每个新出现的数,当cnt=0时id=当前数,不然id=当前数cnt++;否则cnt--;
可以发现如果存在解的话,id一定为最大出现次数的值,但是因为可能中间存在非最大值之间互相抵消的情况
所以还要再扫一边,判断当前值出现次数

1 #include<bits/stdc++.h> 2 #define MAXN 1100 3 #define int long long 4 using namespace std; 5 int M,N,K; 6 int co[MAXN],x[MAXN],y[MAXN],z[MAXN];int a[MAXN]; 7 int maxn_sum=0;int maxn;int S; 8 signed main(){ 9 scanf("%lld%lld",&M,&K); 10 S=(1<<K)-1; 11 for(int i=1;i<=M;++i)scanf("%lld",&co[i]); 12 for(int i=1;i<=M;++i)scanf("%lld",&x[i]); 13 for(int i=1;i<=M;++i)scanf("%lld",&y[i]); 14 for(int i=1;i<=M;++i)scanf("%lld",&z[i]); 15 N=0;int cnt=0;int id=0; 16 for(int i=1;i<=M;++i){ 17 long long last=x[i]; 18 N++; 19 if(cnt==0){cnt=1;id=last;} 20 else if(id==last){cnt++;} 21 else if(id!=last){cnt--;} 22 for(int j=1;j<co[i];++j) { 23 last=(last*y[i]+z[i])&S; 24 N=N+1; 25 if(cnt==0){cnt=1;id=last;} 26 else if(id==last){cnt++;} 27 else if(id!=last){cnt--;} 28 } 29 } 30 if(cnt<1){printf("0 ");return 0;} 31 cnt=0;N=0; 32 for(int i=1;i<=M;++i){ 33 long long last=x[i]; 34 N++; 35 if(id==last){cnt++;} 36 for(int j=1;j<co[i];++j) { 37 last=(last*y[i]+z[i])&S; 38 N=N+1; 39 if(id==last){cnt++;} 40 } 41 } 42 if(2*cnt-N-1>0){printf("%lld ",2*cnt-N-1);} 43 else printf("0 "); 44 /*scanf("%lld",&N); 45 int cnt=0;int id=0; 46 for(int i=1;i<=N;++i){scanf("%lld",&a[i]);} 47 for(int i=1;i<=N;++i){ 48 long long last=a[i]; 49 if(cnt==0){cnt=1;id=last;} 50 else if(id==last){cnt++;} 51 else if(id!=last){cnt--;} printf("i=%lld ",i); 52 } 53 if(cnt-1>0)printf("%lld ",cnt-1); 54 else printf("%lld ",cnt); 55 */ 56 } 57 /* 58 22 59 1 3 3 3 3 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 60 */
T3 race
咕了.............
不咕。
一道trie树好题,想了两节课,(在语文课上想题效率很高QAQ)
首先对于x^2的转化:
既然是排名,我们可以考虑成x^2,是每个大于他的数的集合相乘,即(x1+x2+x3+x4.....)*(x1+x2.......)
(其中每个xi都为1),那么结果可以看成任意一个点对的贡献为一,答案就是点对的个数
既然结果是求异或和,我们联想到trie树(这样说有些牵强.......)
无论如何我们先建棵trie树
那么从1-n的每个i,我们统计这个节点时单独考虑每一位的贡献,我们枚举一个j,一个k
j(k)上的数表示在M-1位到j+1位的数与a[i]的这些位的数相等,那么如果使j,k同时大于a[i],我们只需
确定好异或的第j,k位上的数,其他数随意,这样这两位上的数对他的贡献就是两个位的指针上的size*(1<<M-2)
当j==k时乘的变成(1<<M-1),因为只需确定一位

1 #include<bits/stdc++.h> 2 #define int long long 3 #define MAXN 210000 4 using namespace std; 5 int fa[MAXN][31]; 6 struct node{ 7 int ch[2]; 8 int size; 9 }t[MAXN*20];int n,M; 10 const int mod=1e9+7; 11 int tot=1;int a[MAXN]; 12 void insert(int x){ 13 int p=1;t[p].size++;fa[x][M]=1; 14 for(int i=M-1;i>=0;--i){ 15 int me=(a[x]>>i)&1; 16 if(t[p].ch[me]==0)t[p].ch[me]=++tot; 17 p=t[p].ch[me]; 18 t[p].size++; 19 fa[x][i]=p; 20 } 21 } 22 int ans[MAXN]; 23 void work(int x){ 24 for(int i=0;i<=M-1;++i){ 25 int me1=0,find1=0;int me2=0,find2=0; 26 for(int j=0;j<i;++j){ 27 me1=(a[x]>>i)&1;me2=(a[x]>>j)&1; 28 me1^=1;me2^=1; 29 find1=fa[x][i+1];find2=fa[x][j+1]; 30 ans[x]=(ans[x]+2*t[t[find1].ch[me1]].size*t[t[find2].ch[me2]].size%mod*(1ll<<(M-2ll)))%mod; 31 } 32 me1=(a[x]>>i)&1;me1^=1; 33 find1=fa[x][i+1]; 34 ans[x]=(ans[x]+t[t[find1].ch[me1]].size*t[t[find1].ch[me1]].size%mod*(1<<(M-1)))%mod; 35 } 36 } 37 int sum=0; 38 signed main(){ 39 scanf("%lld%lld",&n,&M); 40 for(int i=1;i<=n;++i){ 41 scanf("%lld",&a[i]); 42 } 43 for(int i=1;i<=n;++i){insert(i);} 44 for(int i=1;i<=n;++i){work(i);} 45 for(int i=1;i<=n;++i){ 46 sum^=ans[i]; 47 } 48 printf("%lld ",sum); 49 }
******************************
思路积累:
x^2的转化,
trie树的应用,
比较大小只需考虑每一位的贡献