题目连接c++
给你 \(k\) 个个位数字和一个数字 \(n\) ,要求找到一个大于等于n的数字,使得不出现 \(k\) 个数.数组
直接枚举就好了,最多枚举到多一位。session
#include<bits/stdc++.h> using namespace std; int n,k; int vis[20]; bool check(int x){ while(x){ int d=x%10; x/=10; if(vis[d])return 0; } return 1; } int main() { //freopen("H:\\c++1\\in.txt","r",stdin); //freopen("H:\\c++1\\out.txt","w",stdout); scanf("%d%d",&n,&k); for(int i=1,x;i<=k;i++)scanf("%d",&x),vis[x]=1; for(int i=n;;i++){ if(check(i)){ printf("%d\n",i);return 0; } } return 0; }
题目连接优化
一个 \(H\) 和 \(W\) 的长方形矩阵,在其左下角的 \(X\) 和 \(Y\) 长方形矩阵不能走,问从左上角往下和往右到右下角的方案数 \(()(H,W<=1e5)\)spa
首先要知道,若没有不能走的格子,从 \((x1,y1)\) 走到 \((x2,y2)\) 的方案数应该是 \(C(x2+y2-x1-y1,x2-x1)\) ,咱们假设左上角坐标位 \((1,1)\) ,右下角坐标位 \((H,W)\) ,那么以 \(x=X\) 为分界线,将可行部分分红两个不一样大小的矩形,那么对于每个方案必须向右穿过这个分界线,那么假设 \(y=i\) ,咱们要从 \((X,i) \to (X+1,i)\) ,咱们只要算出从 \((1,1) \to (X,i)\) 的方案数 \(*\) 从 \((X+1,i) \to (H,W)\) 的方案数,而后把分界线上的每个点累加起来就能够获得答案,预处理阶乘和阶乘的逆元。code
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=2e5+10; const int mod=1e9+7; ll n,m,a,b; ll ksm(ll a,ll b){ ll res=1,t=a; while(b){ if(b&1)res=(res*t)%mod; t=(t*t)%mod; b>>=1; } return res; } ll jc[N],inv[N]; void init(){ jc[0]=inv[0]=1; for(int i=1;i<N;i++)jc[i]=(jc[i-1]*i)%mod,inv[i]=ksm(jc[i],mod-2); } ll C(ll a,ll b){ return ((jc[b]*inv[a])%mod*inv[b-a])%mod; } int main() { //freopen("H:\\c++1\\in.txt","r",stdin); //freopen("H:\\c++1\\out.txt","w",stdout); init(); // 预处理阶乘和逆元 scanf("%lld%lld%lld%lld",&n,&m,&a,&b); ll ans=0; for(int i=1;i<=n-a;i++){ ll ans1=C(b-1,b+i-2); //分界线两个对应的点 ll ans2=C(m-b-1,n-i+m-b-1); ans=(ans+ans1*ans2)%mod; } printf("%lld\n",ans); return 0; }
给定 \(,,X,Y,Z\) ,要求生成一个 \(n\) 个数字的序列,每一个数字为 \(1-10\) ,问全部可能的序列中知足条件:存在 \(1<=x<y<z<w<=n\) ,使得 \(\sum^{x}_{y-1}{a_i}=X,\sum^{y}_{z-1}{a_i}=Y,\sum^{z}_{w-1}{a_i}=Z\) ,的序列个数是多少。 \((X<=5,Y<=7,Z<=5,n<=40)\)队列
首先对于这种数据范围很小的题目应该要考虑状压dp来解决,首先对于一个数字 \(5\) ,咱们能够用二进制 \(10000\) 来表示,对于要造成连续的三段和为 \(,,2,3,1\) 的状态能够用二进制 \(10 100 1\) 来表示,将它们拼接起来,那么对于一个序列 \(,,,2,1,2,1\) 的状态就能够用二进制 \(10 1 10 1\) ,能够发现上面 \(101001\&101101=101001\) 这就表示 \(,,,2,1,2,1\) 序列是知足连续的三段和为 \(,,2,3,1\) 的。经过这样构造咱们就能够进行状态的转移了,咱们应该求得是序列不知足条件的个数,最后在减去。字符串
#include<bits/stdc++.h> using namespace std; const int N=(1<<18); const int mod=1e9+7; int dp[50][N]; int n,a,b,c; int main() { //freopen("H:\\c++1\\in.txt","r",stdin); //freopen("H:\\c++1\\out.txt","w",stdout); scanf("%d",&n); scanf("%d",&a);scanf("%d",&b);scanf("%d",&c); int bz=(1<<(a-1))|(1<<(a+b-1))|(1<<(a+b+c-1));//目标状态 int mx=(1<<(a+b+c));//总共的状态数 dp[0][0]=1;//初始化 int p=1; for(int i=1;i<=n;i++){ p=(1ll*10*p)%mod;//计算总共的方案数 for(int j=0;j<mx;j++){//枚举全部状态 if(dp[i-1][j]==0)continue;//上一个此状态无解 for(int k=1;k<=10;k++){//枚举每种方案 int now=(j<<k)|(1<<(k-1));//更新状态 now&=(mx-1);//防止溢出 if((now&bz)!=bz){//不能构成X,Y,Z dp[i][now]=(dp[i][now]+dp[i-1][j])%mod; } } } } int ans=p; for(int i=0;i<mx;i++){ ans=(ans-dp[n][i]+mod)%mod;// } printf("%d\n",ans); return 0; }
给定 \(N\) 个字符串,选择一些字符串使得它们的总长为 \(K\) ,而且它们按照顺序拼接起来的字典序最小,保证有解。\((N<=2000,K<=1e4,len_i<=K,\sum{len_i}<=1e6)\)get
首先必然要预处理一个\(dp[i][j]\),表示使用 \(i-n\) 的字符串可否构成 \(j\)长度的字符串,使用 \(bitset\) 优化01背包string
咱们将可使用的字符串的第 \(1\) 位加入队列,对于答案的每一位进行构造,对于第 \(i\) 位必然是队列中的全部字符的最小值,接下来,更新队列,若是当前位为该字符串的结尾,那么表示咱们能够将其后面的字符串的第一位加入队列,若是未到结尾就添加该字符串的后一位。
(这个作法不是正解,可是复杂度还行,正解使用了 \(exkmp\) ,有研究研究)
//这题很玄,可能会re或者wa #include<bits/stdc++.h> using namespace std; bitset<10010> ok[2010]; pair<int,int> p[2][10010]; char s[2010][10010],ans[1000010]; int len[2010],n,k,cnt=0,ncnt=0; int main() { scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) scanf("%s",s[i]+1),len[i]=strlen(s[i]+1); ok[n+1][0]=1; for (int i=n;i>=1;i--) ok[i]=ok[i+1]|(ok[i+1]<<len[i]);//01背包处理能够拼成的长度 for (int i=1;i<=n;i++) if (ok[i+1][k-len[i]]) p[0][++cnt]=make_pair(i,1);//加入,使用滚动数组 int f=0; for (int i=1;i<=k;i++) { char mi='z'; for (int j=1;j<=cnt;j++) mi=min(mi,s[p[f][j].first][p[f][j].second]);//贪心选择最小字符 ans[i]=mi; int mx=n+1;//初始化为大值 ncnt=0; for (int j=1;j<=cnt;j++) { int id=p[f][j].first,pos=p[f][j].second; if (s[id][pos]!=mi) continue; if (pos==len[id]) mx=min(mx,id);//当前字符串结束,能够选择当前字符串后面的因此字符串 else p[f^1][++ncnt]=make_pair(id,pos+1);//继续使用这个字符串 } for (int j=mx+1;j<=n;j++) if (k-len[j]-i>=0&&ok[j+1][k-len[j]-i]) p[f^1][++ncnt]=make_pair(j,1);//判断是否能够用该字符串 f^=1;// cnt=ncnt;// } printf("%s\n",ans+1); }