跟着训练赛做的,每道题都学到很多,这次的数据都比较好心,输入简单,思路容易想,但是代码都有点蛋疼
- hdu2845 Beans 二次DP
/* ID: neverchanje PROG: LANG: C++11 */ #include<vector> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdio> #include<set> #include<queue> #include<map> using namespace std; int n,m,t; int dp[200000],p[200000]; int main(){ // freopen(".in","r",stdin); // freopen(".out","w",stdout); while(cin>>m>>n){ memset(dp,0,sizeof(dp)); for(int i=1;i<=m;i++){ dp[0]=0; scanf("%d",&dp[1]); for(int j=2;j<=n;j++) { scanf("%d",&t); dp[j] = max( dp[j-2]+t , dp[j-1] ); } p[i]=dp[n]; } memset(dp,0,sizeof(dp)); dp[1]=p[1]; for(int i=2;i<=m;i++){ dp[i] = max( dp[i-2]+p[i] , dp[i-1] ); } cout<<dp[m]<<endl; } return 0; } /* DESCRIPTION: 如果只有一行的话,最大不连续子序列和为 dp[i][0] = max(dp[j][1]) (j<i) dp[i][1] = dp[i-1][0] + a[i] dp[i]为以i结尾的子序列和 但是这样有On^2 如果是以dp[i]表示在i之前的最大不连续子序列和的话 dp[i] = max( dp[i-2] + a[i] , dp[i-1] ) */
- hdu2846 Repository Trie树变形
/* ID: neverchanje PROG: LANG: C++11 */ #include<vector> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdio> #include<set> #include<queue> #include<map> using namespace std; int n,q; char s[21]; struct node{ node* ch[26]; int val; int id; node(){ for(int i=0;i<26;i++) ch[i]=NULL; val=0; id=-1; } }; node root; int idx(char& x){ return x-'a'; } void insert(char* s,int id){ int len=strlen(s),t; node* p=&root; for(int i=0;i<len;i++){ t=idx(s[i]); if(p->ch[t]==NULL) p->ch[t]=new node; p=p->ch[t]; if(p->id==id) continue; (p->val)++;/////////////// p->id=id; } } int query(char* s){ int len=strlen(s),t; node* p=&root; for(int i=0;i<len;i++){ t=idx(s[i]); if(p->ch[t]==NULL) return 0; p=p->ch[t]; } return p->val; } int main(){ // freopen(".in","r",stdin); // freopen(".out","w",stdout); cin>>n; getchar(); for(int i=0;i<n;i++){ gets(s); int len=strlen(s); for(int j=0;j<len;j++) insert(s+j,i); } cin>>q;getchar(); for(int i=0;i<q;i++) { gets(s); printf("%d ",query(s)); } return 0; } /* DESCRIPTION: 每一个字符串都要被分解成子串,然后存到trie树中,但是这样会出现重复的情况,同一个字符串中的子串在trie树上的节点需要绑定一个id,如果id相同,则计数不能加1 可画图理解 */
- hdu2847 Binary String 暴力枚举+lcs
/* ID: neverchanje PROG: LANG: C++11 */ #include<vector> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdio> #include<set> #include<queue> #include<map> using namespace std; char s[30]; int k,bin,la,lb; int a[30];//保存原串 int b[30];//保存改动后的串 int m;//倍数 int nz,no; int nzz,noo;//先比较0和1的个数来剪枝 int dp[30][30]; int lcs(int* a,int* b,int la,int lb){ memset(dp,0,sizeof(dp)); for(int i=1;i<=la;i++){ for(int j=1;j<=lb;j++){ if(a[i]==b[j]) dp[i][j] = dp[i-1][j-1]+1; else dp[i][j] = max(dp[i-1][j],dp[i][j-1]); } } return dp[la][lb]; } int main(){ // freopen(".in","r",stdin); // freopen(".out","w",stdout); while(scanf("%s%d",s,&k)!=EOF){ la = strlen(s); nz=no=0; memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for(int i=1;i<=la;i++){ a[i]=s[i-1]-'0'; if(a[i]==0) nz++; else no++; } bin=0; for(int i=la-1;i>=0;i--){//化成十进制 bin+=a[la-i]*(1<<i); } if(bin==0) { cout<<0<<endl; continue; } m=bin/k; if(m*k!=bin) ++m; while(1){ bin=m*k; nzz=noo=lb=0; for(int i=1;bin>0;i++)//逆序存储 { b[i]=bin&1; bin=bin>>1; lb++; if(b[i]==0) nzz++; else noo++; } if(nzz<nz || noo<no){ m++;continue; } int l=1,r=lb,t; while(l<r){//因为a是顺序的,也要把b转成顺序 t=b[l];b[l]=b[r];b[r]=t; l++;r--; } // for(int i=1;i<=lb;i++) cout<<b[i]; if(lcs(a,b,la,lb)!=la) { m++; continue; } else { for(int i=1;i<=lb;i++) printf("%d",b[i]); printf(" "); break; } } } return 0; } /* DESCRIPTION: 暴力: 对于二进制数bin,要想整除k,可以暴力枚举k的倍数。判断bin能否达到 只是还要有限制条件: bin的1和0的数目不能比原来少,即使1和0的数目一样了,相对位置也不能变 所以要用到lcs,如果lcs最开始的二进制长度 则继续 注意: 若bin==0 则答案为0 */
- hdu2848 Number Cutting Game 博弈DFS (这题太难打了,细节各种错)
/* ID: neverchanje PROG: LANG: C++11 */ #include<vector> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdio> #include<set> #include<queue> #include<map> using namespace std; long long n;//大数居然用long long.....fuck int k; long long deci[23]; int solve(); int length(long long x){ int len=0; while(x){ len++; x/=10; } return len; } void dfs(long long nn,long long res,int kk, int& yes){ //对一个数进行拆分操作 // printf("%d %d %d %d " ,nn,res,kk,yes); if(yes) return; int len=length(nn); if(len<kk){ yes=0; return; } if(kk==1){ res+=nn; n=res; if(!solve()) { yes=1; return; } } for(int i=len-1;i>=1;i--){ // cout<<"break "; dfs(nn/deci[i],res+nn%deci[i],kk-1,yes); if(yes) return; } } int solve(){ //判断这个数能不能让使用这个操作的一方赢 int len=length(n); if(len<k) return 0; if(len-k+2<k) return 1; long long nn=n; int yes=0; dfs(nn,0,k,yes); return yes; } int main(){ deci[0]=1; for(int i=1;i<=20;i++) deci[i]=deci[i-1]*10; while(cin>>n>>k) { cout<<solve()<<endl; } return 0; } /* DESCRIPTION: length(n)<k,则输 length(n)==k 能保证必赢 9|9|9 3 9|9 2 length(n)==k+1 不能保证必赢,也不能保证必输 9|9|99 3 99|9 2 用k把一个数分解出最大数时,如果先分解出k-1位,后面都分解成1位,这样保证加起来最大,而这个最大数最多只有length(n)-k+2位 9|999 2 9|9|9999 3 9|9|999 3 9|9|9|9999 4 如果length(n)-k+2<k 对手输,这种方案必赢,所以一定会取,length(n)==k的方案也包含在里面 */
- 这题没看懂,以后回来做