2016/10/20

hdu5908

划分子序列为等长子串,这些子串要求两两匹配,匹配的含义是各个数字出现的次数一样。10w规模。

显然剪枝的方法就是利用子长度为总长的约数。匹配其实所有都和第一个子序列去匹配就好了。先++统计第一个,其余的

遇到一次--,全部是0就匹配成功。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<string>
 6 #include<cmath>
 7 #include<set>
 8 #include<map>
 9 #include<stack>
10 #include<queue>
11 #include<algorithm>
12 #include<sstream>
13 using namespace std;
14 #define ll long long
15 #define LL long long
16 #define inf 0x3f3f3f3f
17 #define llinf 0x3f3f3f3f3f3f3f3f
18 #define FOR(i,a,b) for(int i=a;i<=b;i++)
19 #define FORD(i,a,b) for(int i=b;i>=a;i--)
20 #define fp freopen("/Volumes/未命名2/Downloads/acm/in.txt","r",stdin)
21 #define ptarr(a,x,y) for(int _=x;_<=y;_++) if(_!=y) cout<<a[_]<<" ";else cout<<a[_]<<endl;
22 #define pt1(a) cout<<a<<endl;
23 #define pt2(a,b) cout<<a<<" "<<b<<endl;
24 #define pt3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
25 #define pt4(a,b,c,d) cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
26 #define ln1 cout<<"----------------------"<<endl;
27 #define ln2 cout<<"~~~~~~~~~~~~~~~~~~~~~~"<<endl;
28 #define CLR(a,b) memset(a,b,sizeof(a));
29 struct node{
30     int a, b;
31     bool operator<(const node& rhs)const {
32         if(a==rhs.a) 
33             return b<rhs.b;
34         else return a<rhs.a;
35     } 
36 };
37 int T,n,m,K;
38 #define maxn 200000
39 int a[maxn],cnt[maxn];
40 void read(){
41     cin>>n;
42     FOR(i,1,n) cin>>a[i];
43 }
44 void solve(){
45     vector<int>ans;
46     FOR(len,1,n)
47     {
48         if(n%len!=0) continue;
49         else
50         {
51             int l=1,r=len,flg=1;
52             for(l=1,r=len;r<=n;l+=len,r+=len)
53             {
54                 FOR(k,1,len) cnt[a[k]]++;
55                 FOR(k,l,r) if(cnt[a[k]]) cnt[a[k]]--;
56                 FOR(k,1,len) if(cnt[a[k]]!=0) cnt[a[k]]=0,flg=0;
57 
58             }
59             if(flg) ans.push_back(len);
60             FOR(k,1,len) cnt[a[k]]=0;
61         }
62     }
63     int sz=ans.size();
64     FOR(k,0,sz-1)
65     {
66         if(k!=sz-1) printf("%d ",ans[k]);
67         else printf("%d\n",ans[k]);
68     }
69 }
70 int main()
71 {
72     cin>>T;
73     while(T--)
74     {
75         read();
76         solve();
77     }
78     return 0;
79 }
View Code

 

hdu5909

树里面选取非空一个子树使得所有的点权异或和作为树的值。求出各种树的值下的方案数%(1e9+10)

规模:值不超过m(m<1024),点数目不超过1000.

题解:方案选择类的问题常用的一个化简的思路就是有序化方法。虽然树的选择有很多种。但是只要钦定了一个根,使得总树称为有根树,那么任何一种方案都可以转化为偏序的树形dp的问题。接下来就考虑dp方程是i表示根,j表示总异或和,d[i][j]=d[i][j]+(s2^s1==j)sum(d[i][s1]*d[x][s2]),这里需要解释下为什么想到,这个问题的本质是选取若干子树以及它们的值使得异或和为j,但是这样显然不能做,但是依然考虑有序化的话其实子树可以按照偏序选择,用背包dp兜住。但是这个方程规模过大,注意到这是一个卷积,所以用fwt加速。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<string>
#include<cctype>
#include<stack>
#include<queue>
#include<set>
#include<sstream>
#include<map>
using namespace std;
#define FORD(i,k,n) for(int i=n;i>=k;i--)
#define FOR(i,k,n) for(int i=k;i<=n;i++)
#define CLR(a,b) memset(a,b,sizeof(a));
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define LL long long
#define ull unsigned long long
#define i64 long long
#define u32 unsigned int
#define u64 unsigned long long
#define ptb(b,a){int tmp=a;string s;do{s+=tmp%2+'0';tmp/=2;}while(tmp);reverse(s.begin(),s.end());cout<<"bin "<<b<<"="<<s<<endl;}
#define pta(i,a,f,b) {FOR(i,f,b) cout<<a[i]<<" "; printf("\n");}
#define pt(a,b) cout<<a<<"="<<b<<endl
#define pt1(a) cout<<a<<endl
#define pt2(a,b) cout<<a<<" "<<b<<endl
#define pt3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl
#define pt4(a,b,c,d) cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl
#define ptl1 cout<<"-------------"<<endl
#define ptl2 cout<<"~~~~~~~~~~~~~~~~"<<endl
#define fp   freopen("in.txt","r",stdin)
#define maxn 2050
int n,m,K,a[maxn],d[maxn][maxn],tmp[maxn],ans[maxn];
const int mod=1e9+7,rev=(mod+1)>>1;  
struct edge
{
    int u,v;
};
vector<edge>e[maxn];
void read()
{
    scanf("%d%d",&n,&m);
    FOR(i,1,n) {
        scanf("%d",&a[i]);
        e[i].clear();
    }
    FOR(i,1,n-1)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        edge tmp;
        tmp.v=v;
        e[u].push_back(tmp);
        tmp.v=u;
        e[v].push_back(tmp);
    }
}
void FWT(int *a,int n)  
{  
    for(int d=1; d<n; d<<=1)  
        for(int m=d<<1,i=0; i<n; i+=m)  
            for(int j=0; j<d; j++)  
            {  
                int x=a[i+j],y=a[i+j+d];  
                a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;   
            }  
}  
  
void UFWT(int *a,int n)  
{  
    for(int d=1; d<n; d<<=1)  
        for(int m=d<<1,i=0; i<n; i+=m)  
            for(int j=0; j<d; j++)  
            {  
                int x=a[i+j],y=a[i+j+d];  
                a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod;   
            }  
}  
  
void work(int *a,int *b,int n)  
{  
    FWT(a,n);  
    FWT(b,n);  
    for(int i=0; i<n; i++)   a[i]=1LL*a[i]*b[i]%mod;  
    UFWT(a,n);  
}  

void dfs(int u,int f)
{
    int sz=e[u].size();
    d[u][a[u]]=1;
    FOR(k,0,sz-1){
        int v=e[u][k].v;
        if(v==f) continue;
        dfs(v,u);
        FOR(s1,0,m*2)  tmp[s1]=d[u][s1];
        work(d[u],d[v],m);
        FOR(s1,0,m*2) d[u][s1]=(d[u][s1]+tmp[s1])%mod;
    }
    FOR(i,0,m) ans[i]=(ans[i]+d[u][i])%mod;
}
void solve()
{
    CLR(d,0);
    CLR(ans,0);
    dfs(1,-1); 
    FOR(i,0,m-1)
    {
        printf("%d%c",ans[i],i==m-1?'\n':' ');
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        read();
        solve();
    }
    return 0;
}
View Code

 

hdu5902 gcd is funny

给定一个序列,每次选取三个,划掉一个,另外两个用它们的gcd代替,经过n-2轮之后显然只剩下两个相同的数字。问最后剩下的数值可能是哪些?

规模:序列规模1000,数值大小1000

题解:经过初步的感觉应该是若干个数的gcd。但是因为最初会删除一个,所以应该是任意n-1个数字的gcd。有的时候奇怪的操作不是为了设置限制,而是不得不这么做。这里为什么要两个用gcd替代两次呢,因为如果只替代一次就不能用经典的gcd容斥进行求解。经典的n-1轮gcd容斥的做法就和floyd很像,而且n-1轮的gcd是允许重复选择一个数字的。

bug:1.没有在gcd容斥里面加flg得到tle

   2.加了flg却忘记了只有产生新的时候才flg=1,if条件忘记写

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<string>
#include<cctype>
#include<stack>
#include<queue>
#include<set>
#include<sstream>
#include<map>
using namespace std;
#define FORD(i,k,n) for(int i=n;i>=k;i--)
#define FOR(i,k,n) for(int i=k;i<=n;i++)
#define CLR(a,b) memset(a,b,sizeof(a));
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define LL long long
#define ull unsigned long long
#define i64 long long
#define u32 unsigned int
#define u64 unsigned long long
#define ptb(b,a){int tmp=a;string s;do{s+=tmp%2+'0';tmp/=2;}while(tmp);reverse(s.begin(),s.end());cout<<"bin "<<b<<"="<<s<<endl;}
#define pta(i,a,f,b) {FOR(i,f,b) cout<<a[i]<<" "; printf("\n");}
#define pt(a,b) cout<<a<<"="<<b<<endl
#define pt1(a) cout<<a<<endl
#define pt2(a,b) cout<<a<<" "<<b<<endl
#define pt3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl
#define pt4(a,b,c,d) cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl
#define ptl1 cout<<"-------------"<<endl
#define ptl2 cout<<"~~~~~~~~~~~~~~~~"<<endl
#define fp   freopen("in.txt","r",stdin)
#define maxn 2000
int n,m,K,T,a[maxn],g[maxn];
struct node
{
    int x,y;
    bool operator<(const node&rhs)const
    {
        if(x!=rhs.x)
            return x<rhs.x;
        else return y<rhs.y;
    }
};
int gcd(int a, int b)
{
    while(b)
    {
        int t = a % b;
        a = b;
        b = t;
    }
    return a;
}
void read()
{
    cin>>n;
    FOR(i,1,n) {
        cin>>a[i];
    }
}
void preprocess()
{
}
void solve()
{
    CLR(g,0);
    int cnt=n-3;
    FOR(i,1,n) {
        FOR(j,i+1,n){
            g[gcd(a[i],a[j])]=1;
        }
    }
    int flg=1;
    while(cnt--&&flg)
    {
        flg=0;
        FOR(i,1,1000)
        {
            if(g[i]==0) continue;
            FOR(j,1,n)
            {
                if(!g[gcd(i,a[j])]){
                    g[gcd(i,a[j])]=1;
                    flg=1;
                }
            }
        }
    }
    int ans[2000],len=0;
    FOR(i,1,1000)
    {
        if(g[i]==1) ans[len++]=i;
    }
    FOR(i,0,len-1)
    {
        printf("%d%c",ans[i],i==len-1?'\n':' ');
    }
}
int main()
{
    cin>>T;
    while(T--)
    {
        read();
        solve();
    }
    return 0;
}
View Code

 

hdu5903 wa

 

hdu5904 LCIS

给定两个10w数值100w序列要求选取子序列数值连续,那么问最长公共上升数值连续子序列是多少?

题解:如果分别求出两个序列的下标偏序的dp然后组合显然会超时,那可以从key的偏序考虑改成value的偏序,按照数值进行dp,那么d[a[i]]=(d[a[i]-1]+1)/1,分别求出两个序列,然后按照值取max(ans,min(f,g))就可以了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<string>
#include<cctype>
#include<stack>
#include<queue>
#include<set>
#include<sstream>
#include<map>
using namespace std;
#define FORD(i,k,n) for(int i=n;i>=k;i--)
#define FOR(i,k,n) for(int i=k;i<=n;i++)
#define CLR(a,b) memset(a,b,sizeof(a));
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define LL long long
#define ull unsigned long long
#define i64 long long
#define u32 unsigned int
#define u64 unsigned long long
#define ptb(b,a){int tmp=a;string s;do{s+=tmp%2+'0';tmp/=2;}while(tmp);reverse(s.begin(),s.end());cout<<"bin "<<b<<"="<<s<<endl;}
#define pta(i,a,f,b) {FOR(i,f,b) cout<<a[i]<<" "; printf("\n");}
#define pt(a,b) cout<<a<<"="<<b<<endl
#define pt1(a) cout<<a<<endl
#define pt2(a,b) cout<<a<<" "<<b<<endl
#define pt3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl
#define pt4(a,b,c,d) cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl
#define ptl1 cout<<"-------------"<<endl
#define ptl2 cout<<"~~~~~~~~~~~~~~~~"<<endl
#define fp   freopen("in.txt","r",stdin)
#define maxn 100005
int n,m,K,T,f[maxn*10],g[maxn*10];
int a[maxn],b[maxn];
struct node
{
    int x,y;
    bool operator<(const node&rhs)const
    {
        if(x!=rhs.x)
            return x<rhs.x;
        else return y<rhs.y;
    }
};
void read()
{
    scanf("%d%d",&n,&m);
    FOR(i,1,n) scanf("%d",&a[i]);
    FOR(i,1,m) scanf("%d",&b[i]);
}
void preprocess()
{
}
void solve()
{
    CLR(f,0);
    CLR(g,0);
    FOR(i,1,n)
    {
        if(f[a[i]-1]!=0) f[a[i]]=f[a[i]-1]+1;
        else f[a[i]]=1;
        // pt3(i,a[i],f[a[i]]);
    }
    FOR(i,1,m)
    {
        if(g[b[i]-1]!=0) g[b[i]]=g[b[i]-1]+1;
        else g[b[i]]=1;
    }
    int ans=-1;
    FOR(i,1,n)
    {
        ans=max(ans,min(f[a[i]],g[a[i]]));
        // pt4(x[a[i]],y[a[i]],x[b[i]],y[b[i]]);
    }
    FOR(i,1,m)
    {
        ans=max(ans,min(f[b[i]],g[b[i]]));
        // pt4(x[a[i]],y[a[i]],x[b[i]],y[b[i]]);
    }
    printf("%d\n",ans);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        read();
        solve();
    }
    return 0;
}
View Code

 

posted @ 2016-10-20 13:32  aidgn  阅读(109)  评论(0编辑  收藏  举报