#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
#define L(x) (1 << (x))
const double PI = acos(-1.0);
typedef long long LL;
#define INF MAX_INT
copy(buf,n,str.c_str)//string转char
sscanf(buf,"%d%d",&a,&b)//串输入处理
sprintf(but,"%.2lf",n)//double转char *
char *itoa(int value, char* string, int radix)//int转char* radix进制
//优读
int read(){
int x=0,f=1;
char ch;
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
template<class T>void read(T &x){//read(n)
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
//大数乘法
string mult(string s,int n){
int i,len = s.length(),temp = 0;
for(i = len - 1;i >= 0;i--)
{
temp = temp + (s[i] - '0')*n;
s[i] = (temp%10)+'0';
temp = temp/10;//进位
}
char c;
while(temp)
{
c = (temp%10)+'0';
s = c + s;
temp /= 10;
}
return s;
}
//大数除法
string div(string a, long long b){//高精度a除以单精度b
string r, ans;
long long d = 0;
if (a == "0") return a;//特判
for (int i = 0; i<a.size(); i++)
{
r += (d * 10 + a[i] - '0') / b + '0';//求出商
d = (d * 10 + (a[i] - '0')) % b;//求出余数
}
long long p = 0;
for (int i = 0; i<r.size(); i++)
if (r[i] != '0') { p = i; break; }
return r.substr(p);
}
//fft优化的大数乘法
const int Maxn = 133015;
double ax[Maxn], ay[Maxn], bx[Maxn], by[Maxn];
char sa[Maxn/2],sb[Maxn/2];
int sum[Maxn];
int x1[Maxn],x2[Maxn];
int revv(int x, int bits)
{
int ret = 0;
for (int i = 0; i < bits; i++)
{
ret <<= 1;
ret |= x & 1;
x >>= 1;
}
return ret;
}
void fft(double * a, double * b, int n, bool rev)
{
int bits = 0;
while (1 << bits < n) ++bits;
for (int i = 0; i < n; i++)
{
int j = revv(i, bits);
if (i < j)
swap(a[i], a[j]), swap(b[i], b[j]);
}
for (int len = 2; len <= n; len <<= 1)
{
int half = len >> 1;
double wmx = cos(2 * PI / len), wmy = sin(2 * PI / len);
if (rev) wmy = -wmy;
for (int i = 0; i < n; i += len)
{
double wx = 1, wy = 0;
for (int j = 0; j < half; j++)
{
double cx = a[i + j], cy = b[i + j];
double dx = a[i + j + half], dy = b[i + j + half];
double ex = dx * wx - dy * wy, ey = dx * wy + dy * wx;
a[i + j] = cx + ex, b[i + j] = cy + ey;
a[i + j + half] = cx - ex, b[i + j + half] = cy - ey;
double wnx = wx * wmx - wy * wmy, wny = wx * wmy + wy * wmx;
wx = wnx, wy = wny;
}
}
}
if (rev)
{
for (int i = 0; i < n; i++)
a[i] /= n, b[i] /= n;
}
}
int solve(int a[],int na,int b[],int nb,int ans[])
{
int len = max(na, nb), ln;
for(ln=0; L(ln)<len; ++ln);
len=L(++ln);
for (int i = 0; i < len ; ++i)
{
if (i >= na) ax[i] = 0, ay[i] =0;
else ax[i] = a[i], ay[i] = 0;
}
fft(ax, ay, len, 0);
for (int i = 0; i < len; ++i)
{
if (i >= nb) bx[i] = 0, by[i] = 0;
else bx[i] = b[i], by[i] = 0;
}
fft(bx, by, len, 0);
for (int i = 0; i < len; ++i)
{
double cx = ax[i] * bx[i] - ay[i] * by[i];
double cy = ax[i] * by[i] + ay[i] * bx[i];
ax[i] = cx, ay[i] = cy;
}
fft(ax, ay, len, 1);
for (int i = 0; i < len; ++i)
ans[i] = (int)(ax[i] + 0.5);
return len;
}
string mul(string sa,string sb)
{
int l1,l2,l;
int i;
string ans;
memset(sum, 0, sizeof(sum));
l1 = sa.size();
l2 = sb.size();
for(i = 0; i < l1; i++)
x1[i] = sa[l1 - i - 1]-'0';
for(i = 0; i < l2; i++)
x2[i] = sb[l2-i-1]-'0';
l = solve(x1, l1, x2, l2, sum);
for(i = 0; i<l || sum[i] >= 10; i++) // 进位
{
sum[i + 1] += sum[i] / 10;
sum[i] %= 10;
}
l = i;
while(sum[l] <= 0 && l>0) l--; // 检索最高位
for(i = l; i >= 0; i--) ans+=sum[i] + '0'; // 倒序输出
return ans;
}
//大数加法
string add(string s1,string s2){
if(s1 == ""&&s2 == "")return "0";
if(s1 == "")return s2;
if(s2 == "")return s1;
string maxx = s1,minn = s2;
if(s1.length() < s2.length())
{
maxx = s2;
minn = s1;
}
int i,a = maxx.length()-1,b = minn.length()-1;
for(i = b;i >=0 ;--i)
{
maxx[a--] += minn[i] - '0';
}
for(i = maxx.length() - 1;i > 0;--i)
{
if(maxx[i] > '9')
{
maxx[i] -= 10;
maxx[i-1]++;
}
}
if(maxx[0] > '9')
{
maxx[0] -= 10;
maxx = '1'+maxx;
}
return maxx;
}
//大数减法
string bigIntegerSub(char *s1,char *s2){
if(s1 == s2)
return "0"; //相等
int len1 = strlen(s1),len2 = strlen(s2);
if(len1 > len2)
return subInfo(s1,s2);
else if(len1 < len2)
return "-" + subInfo(s2,s1); //负数
else { //长度相等时判断大小
for(int i = 0; i < len1; i++){
if(s1[i]-'0' > s2[i]-'0')
return subInfo(s1,s2);
else if(s1[i]-'0' < s2[i]-'0')
return "-" + subInfo(s2,s1);
}
}
}
//只限大的非负整数减小的非负整数
const int L=110;
string sub(string a,string b)
{
string ans;
int na[L]={0},nb[L]={0};
int la=a.size(),lb=b.size();
for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
int lmax=la>lb?la:lb;
for(int i=0;i<lmax;i++)
{
na[i]-=nb[i];
if(na[i]<0) na[i]+=10,na[i+1]--;
}
while(!na[--lmax]&&lmax>0) ;lmax++;
for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
return ans;
}
//高精度求模
int mod(string a,int b)//高精度a除以单精度b
{
int d=0;
for(int i=0;i<a.size();i++) d=(d*10+(a[i]-'0'))%b;//求出余数
return d;
}
//高精度阶乘
const int L=100005;
int a[L];
string fac(int n)
{
string ans;
if(n==0) return "1";
fill(a,a+L,0);
int s=0,m=n;
while(m) a[++s]=m%10,m/=10;
for(int i=n-1;i>=2;i--)
{
int w=0;
for(int j=1;j<=s;j++) a[j]=a[j]*i+w,w=a[j]/10,a[j]=a[j]%10;
while(w) a[++s]=w%10,w/=10;
}
while(!a[s]) s--;
while(s>=1) ans+=a[s--]+'0';
return ans;
}
//快速幂
ll powermod(ll a,ll b){
ll res = 1;
while(b)
{
if(b&1) res *= a;
a *= a;
b >>=1;
}
return res;
}
//高精度快速幂
const int Maxn = 133015;
double ax[Maxn], ay[Maxn], bx[Maxn], by[Maxn];
char sa[Maxn/2],sb[Maxn/2];
int sum[Maxn];
int x1[Maxn],x2[Maxn];
int revv(int x, int bits)
{
int ret = 0;
for (int i = 0; i < bits; i++)
{
ret <<= 1;
ret |= x & 1;
x >>= 1;
}
return ret;
}
void fft(double * a, double * b, int n, bool rev)
{
int bits = 0;
while (1 << bits < n) ++bits;
for (int i = 0; i < n; i++)
{
int j = revv(i, bits);
if (i < j)
swap(a[i], a[j]), swap(b[i], b[j]);
}
for (int len = 2; len <= n; len <<= 1)
{
int half = len >> 1;
double wmx = cos(2 * PI / len), wmy = sin(2 * PI / len);
if (rev) wmy = -wmy;
for (int i = 0; i < n; i += len)
{
double wx = 1, wy = 0;
for (int j = 0; j < half; j++)
{
double cx = a[i + j], cy = b[i + j];
double dx = a[i + j + half], dy = b[i + j + half];
double ex = dx * wx - dy * wy, ey = dx * wy + dy * wx;
a[i + j] = cx + ex, b[i + j] = cy + ey;
a[i + j + half] = cx - ex, b[i + j + half] = cy - ey;
double wnx = wx * wmx - wy * wmy, wny = wx * wmy + wy * wmx;
wx = wnx, wy = wny;
}
}
}
if (rev)
{
for (int i = 0; i < n; i++)
a[i] /= n, b[i] /= n;
}
}
int solve(int a[],int na,int b[],int nb,int ans[])
{
int len = max(na, nb), ln;
for(ln=0; L(ln)<len; ++ln);
len=L(++ln);
for (int i = 0; i < len ; ++i)
{
if (i >= na) ax[i] = 0, ay[i] =0;
else ax[i] = a[i], ay[i] = 0;
}
fft(ax, ay, len, 0);
for (int i = 0; i < len; ++i)
{
if (i >= nb) bx[i] = 0, by[i] = 0;
else bx[i] = b[i], by[i] = 0;
}
fft(bx, by, len, 0);
for (int i = 0; i < len; ++i)
{
double cx = ax[i] * bx[i] - ay[i] * by[i];
double cy = ax[i] * by[i] + ay[i] * bx[i];
ax[i] = cx, ay[i] = cy;
}
fft(ax, ay, len, 1);
for (int i = 0; i < len; ++i)
ans[i] = (int)(ax[i] + 0.5);
return len;
}
string mul(string sa,string sb)
{
int l1,l2,l;
int i;
string ans;
memset(sum, 0, sizeof(sum));
l1 = sa.size();
l2 = sb.size();
for(i = 0; i < l1; i++)
x1[i] = sa[l1 - i - 1]-'0';
for(i = 0; i < l2; i++)
x2[i] = sb[l2-i-1]-'0';
l = solve(x1, l1, x2, l2, sum);
for(i = 0; i<l || sum[i] >= 10; i++) // 进位
{
sum[i + 1] += sum[i] / 10;
sum[i] %= 10;
}
l = i;
while(sum[l] <= 0 && l>0) l--; // 检索最高位
for(i = l; i >= 0; i--) ans+=sum[i] + '0'; // 倒序输出
return ans;
}
string Pow(string a,int n)
{
if(n==1) return a;
if(n&1) return mul(Pow(a,n-1),a);
string ans=Pow(a,n/2);
return mul(ans,ans);
}
//矩阵快速幂
struct Matrix {
int m[N][N];
Matrix(){}
};
void Init(Matrix &matrix){
for(int i = 0;i < N; i++)scanf("%d",&matrix.m[0][i]);
for(int i = 1;i < N; i++){
for(int j = 0;j < N; j++){
if(i == (j+1))matrix.m[i][j] = 1;
else matrix.m[i][j] = 0;
}
}
}
Matrix Mul(Matrix &a,Matrix &b){//矩阵相乘
Matrix c;
for(int i = 0; i < N; i++){
for(int j = 0;j < N; j++){
c.m[i][j] = 0;
for(int k = 0; k < N; k++)c.m[i][j] += a.m[i][k]*b.m[k][j];
c.m[i][j] %= Mod;
}
}
return c;
}
Matrix Pow(Matrix& matrix, int k) {//矩阵幂
Matrix res;
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
if (i == j) res.m[i][j] = 1;
else res.m[i][j] = 0;
while (k) {
if (k & 1) res = Mul(matrix,res);
k >>= 1;
matrix = Mul(matrix,matrix);
}
return res;
}
//线性筛
int prime[maxn]; //标识
int *p = new int[maxn/2+1];//素数数组
int fun(){
memset(prime,0,sizeof(int)*(maxn+1));
memset(p,0,sizeof(int)*(maxn/2));
int i,j,t = 0;
for(i = 2;i <= maxn;i++)
{
if(prime[i] == 0)
{
p[t++] = i;
}
for(j = 0;j < t && i*p[j] <= maxn;j++)
{
prime[i*p[j]] = 1;
if(i%p[j] == 0)break;
}
}
return t;
}
//gcd
int gcd(int a,int b){
if(b > a)swap(a,b);
int temp;
while(b != 0)
{
if(b > a)swap(a,b);
temp = a % b;
a = b;
b = temp;
}
return a;
}
//扩展gcd
LL exgcd(LL a,LL b,LL &x,LL &y){
if(b == 0){
x = 1;
y = 0;
return a;
}
LL d = exgcd(b,a%b,x,y);
LL t = x;
x = y;
y = t-(a/b)*y;
return d;
}
//卢卡斯逆元
LL Lucas(LL n,LL k) //Lucas定理递归
{
if (k == 0) //递归终止条件
return 1;
else
return C(n % mod , k % mod) * Lucas(n / mod , k / mod) % mod;
}
//组合数公式
LL C(LL n , LL k) //费马小定理求逆元
{
if (k > n)
return 0;
else
return fac[n] * (quick(fac[k] * fac[n-k] % mod , mod - 2)) % mod;
}
//欧拉函数 对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1)
int phi[maxn+1], phi_psum[maxn+1];
int euler_phi(int n){
int m = sqrt(n+0.5);
int ans = n;
for(int i = 2; i < m; i++)if(n % i == 0){
ans = ans/i*(i-1);
while(n % i == 0)n /= i;
}
if(n > 1)ans = ans/n*(n-1);
return ans;
}
void phi_table(int n) {//筛素数的方法,求解1~n所有数的欧拉phi函数值
phi[1] = 0; //这里不计算第一个1,1和1,1是重复的,等下直接2*phi_psum[n] + 1
for(int i = 2; i <= n; i++) if(phi[i] == 0)
for(int j = i; j <= n; j += i) {
if(phi[j] == 0) phi[j] = j;
phi[j] = phi[j] / i * (i-1);
}
}
//二分法
int cmp(const void *a, const void *b) {
return *(int *) a - *(int *) b;
}
int bs(int *arr,int L,int R,int target){//普通的二分查找
while( L <= R){
int mid = (L) + (R-L)/2;
if(arr[mid] == target)
return mid;
if(arr[mid] > target)
R = mid - 1;
else
L = mid + 1;
}
return -1; // not find
}
int firstEqual(int arr[], int L, int R, int target) {//求最小的i,使得a[i] = target,若不存在,则返回-1
while (L < R) {
int mid = L + (R - L) / 2;
if (arr[mid] < target)
L = mid + 1;
else
R = mid;
}
if (arr[L] == target)
return L;
return -1;
}
int lastEqualNext(int arr[], int L, int R, int target) {//求最大的i的下一个元素的下标(c++中的upperbound函数),使得a[i] = target,若不存在,则返回-1
while (L < R) {
int m = L + (R - L) / 2;
if (arr[m] <= target)
L = m + 1;
else
R = m;
}
if (arr[L - 1] == target)
return L;
return -1;
}
int lastEqual(int arr[], int L, int R, int target) {//求最大的i,使得a[i] = target,若不存在,则返回-1
while (L < R) {
int mid = L + ((R + 1 - L) >> 1);//向上取整
if (arr[mid] <= target)
L = mid;
else
R = mid - 1;
}
if (arr[L] == target)
return L;
return -1;
}
int firstLarge(int arr[], int L, int R, int target) {//求最小的i,使得a[i] > target,若不存在,则返回-1
while (L < R) {
int m = L + ((R - L) >> 1);//向下取整
if (arr[m] <= target)
L = m + 1;
else
R = m;
}
if (arr[R] > target)
return R;
return -1;
}
int lastSmall(int arr[], int L, int R, int target) {//求最大的i,使得a[i] < target,若不存在,则返回-1
while (L < R) {
int m = L + ((R + 1 - L) >> 1);//向上取整
if (arr[m] < target)
L = m;
else
R = m - 1;
}
if (arr[L] < target)
return L;
return -1;
}
//kmp
void getNext(int *p,int next[]) { //优化后的求next数组的方法
int len = m;
next[0] = -1; //next 数组中的 最大长度值(前后缀的公共最大长度) 的第一个 赋值为 -1
int k = -1,j = 0;
while (j < len - 1) {
if (k == -1 || p[j] == p[k]) { //p[k]表示前缀 p[j] 表示后缀
k++; j++;
if(p[j] != p[k])next[j] = k;
else next[j] = next[k]; //因为不能出现p[j] = p[ next[j ]],所以当出现时需要继续递归,k = next[k] = next[next[k]]
}
else k = next[k];
}
}
int KMPSerach(int *s, int *p) {
int sLen = n,pLen = m;
int i = 0, j = 0;
while (i < sLen && j < pLen) {
if (j == -1 || s[i] == p[j])i++, j++;
else j = nexts[j];
}
if (j == pLen)return i - j;
else return -1;
}
//背包问题
//01背包
for(int i = 1;i <= n;i++){
for(int j = V;j >= w[i];j--){
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
}
//完全背包
for(int i = 0;i < n;i++){
for(int j = w[i];j <= e-s;j++){
dp[j] = min(dp[j],dp[j-w[i]]+v[i]);
}
}
//多重背包
for(int i = 0;i < n;i++){
for(int k = 0;k < b[i];k++){
for(int j = n;j >= v[i];j--){
dp[j] = max(dp[j],dp[j-v[i]]+w[i]);
}
}
}
//01背包 ,记录路径
const int N = 1e5 + 10;
int pre[N],dp[N],v[N],ans[N];
void p(int x){
if(pre[x] == 0){
cout<<ans[x];return;
}
p(pre[x]);
cout<<' '<<ans[x];
}
int main(){
ios_base::sync_with_stdio(0);
int n,m;cin>>n>>m;
for(int i = 0;i < n;i++)cin>>v[i];
for(int i = 0;i < N;i++)pre[i] = -1,dp[i] = -INF;
sort(v,v+n);
dp[0] = 0; //和01背包类似,因为是恰好装满,其他只要赋上负无穷
for(int i = 0;i < n;i++){
for(int j = m;j >= v[i];j--){
if(dp[j] <= dp[j-v[i]]+1){
dp[j] = dp[j-v[i]]+1;
ans[j] = v[i];
pre[j] = j - v[i];
}
}
}
if(dp[m] <= 0) cout<<"No Solution";
else p(m);
cout<<endl;
return 0;
}
//最大线段和
int maxsum(int n,int b[]){
int sum = 0,temp = 0;
for(int i = 0;i < n;i++)
{
temp>0?temp+=b[i]:temp=b[i];
if(temp > sum)sum = temp;
}
return sum;
}
int maxsum2(int m,int n,int **a){
int *b = new int[n],sum = 0;
for(int i = 0;i < m;i++)
{
for(int k = 0;k < n;k++)
b[k] = 0;
for(int j = i;j < m;j++)
{
for(int k = 0;k < n;k++)
b[k] += a[j][k];
int temp = maxsum(n,b);
if(temp > sum)sum = temp;
}
}
return sum;
}
//全排列(去重)
void permutation(int *arr,int *p,int n,int cur){
if(cur == n){
for(int i = 0; i < n; i++)
printf("%d ",arr[i]);
printf("\n");
}else for(int i = 0; i < n; i++)if(!i || p[i] != p[i-1]){
int c1 = 0, c2 = 0;
for(int j = 0; j < n; j++)
if(p[j] == p[i]) // 重复元素的个数
c1++;
for(int j = 0; j < cur; j++)
if(arr[j] == p[i]) // 前面已经排列的重复元素的个数
c2++;
if(c2 < c1){
arr[cur] = p[i];
permutation(arr, p, n, cur+1);
}
}
}
//全排列(函重)
void permutation(int arr[], int cur, int n){
if( cur == n){
for(int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}
else for(int i = cur; i < n; i++){
swap(arr[i], arr[cur]);
permutation(arr, cur+1, n);
swap(arr[i], arr[cur]);
}
}
//n后排列
int vis[n],path[n],count = 0;
memset(path,0,sizeof(path));memset(vis,0,sizeof(vis));DFS(1);
void DFS(int tmp){//tmp目前排了多少皇后,x目前排的列,path具体排法
if (tmp == 9)
{ //8个行均排满
count++;
for (int i = 1; i <= 8; i++)
{
printf("%d ",path[i]);
}
printf(" %d\n",count);
return;
}
for (int i = 1; i <= 8; i++)//8个列循环扫描
{
if (!vis[i])
{
bool flag = false;
for (int j = 1; j < tmp; j++)
{
if (tmp - i == j - path[j] || tmp + i == path[j] + j)
{
flag = true;
break;
}
}
if (flag) continue;
vis[i] = true;
path[tmp] = i;//标记位置
DFS(tmp + 1);//下一行
vis[i] = false;
path[tmp] = 0;
}
}
}
//并查集
int parent[maxn], rank[maxn]; //parent[]保存祖先,rank记录每个'树的高度'
void init(){
for(int i = 0; i < maxn; i++)parent[i] = i; //注意这里
for(int i = 0; i < maxn; i++)rank[i] = 1;
}
int findRoot(int v){
while(parent[v] != v){
parent[v] = parent[parent[v]]; // 路径压缩
v = parent[v];
}
return v;
}
void unions(int a, int b){
int aRoot = findRoot(a);
int bRoot = findRoot(b);
if (aRoot == bRoot)
return;
if (rank[aRoot] < rank[bRoot])
parent[aRoot] = bRoot;
else if(rank[aRoot] > rank[bRoot]){
parent[bRoot] = aRoot;
}else{
parent[aRoot] = bRoot;
rank[bRoot]++;
}
}
int is_same(int x,int y){ //检查是不是在同一个集合中
return findRoot(x) == findRoot(y);
}
//树状数组
int lowbit(int x){//计算2^k
return x&(-x);
}
void update(int i,int val){//更新数组的值
while(i < maxn){ //注意这里是最大的x,没有记录所以用maxn,不能用n
c[i] += val;
i += lowbit(i); //不断的往上面更新
}
}
int sum(int i){//查询
int s = 0;
while(i > 0){
s += c[i];
i -= lowbit(i); //不断的往下面加
}
return s;
}
//LCS
int LCS(char *s1,char *s2){
int len1 = strlen(s1)-1,len2 = strlen(s2)-1;//注意例如 abcfbc的strlen(s1)为7,所以是strlen(s1) - 1
for(int i = 0; i <= len1; i++) dp[i][0] = 0;
for(int i = 0; i <= len2; i++) dp[0][i] = 0;
for(int i = 1; i <= len1; i++){
for(int j = 1; j <= len2; j++)
if(s1[i] == s2[j]){
dp[i][j] = dp[i-1][j-1] + 1;
path[i][j] = 1;
}
else if(dp[i-1][j] >= dp[i][j-1]) {
dp[i][j] = dp[i-1][j];
path[i][j] = 2;
}
else {
dp[i][j] = dp[i][j-1];
path[i][j] = 3;
}
}
return dp[len1][len2];
}
//堆优化dijkstra
struct Node{
int v,w;
Node(int v,int w):v(v),w(w){}
bool operator < (const Node&rhs) const {
return rhs.w < w;
}
};
vector<Node>G[maxn];
bool vis[maxn];
int d[maxn];
int n,m;
void init(){
for(int i = 0; i < maxn; i++)G[i].clear();
for(int i = 0; i < maxn; i++)vis[i] = false;
for(int i = 0; i < maxn; i++)d[i] = INF;
}
int dijkstra(int s,int e){ //传入起点终点
priority_queue<Node>q;
q.push(Node(s,0));
d[s] = 0;
while(!q.empty()){
Node now = q.top(); q.pop();
int v = now.v;
if(vis[v])continue;
vis[v] = true;
for(int i = 0; i < G[v].size(); i++){
int v2 = G[v][i].v;
int w = G[v][i].w;
if(!vis[v2] && d[v2] > w+d[v]){
d[v2] = w+d[v];
q.push(Node(v2,d[v2]));
}
}
}
return d[e];
}
//用于最长非递减子序列种的lower_bound函数
int cmp(int a,int b){
return a <= b;
}
//最长上升子序列
//dp[i]表示长度为i+1的上升子序列的最末尾元素 找到第一个比dp末尾大的来代替
int LIS(int n){
memset(dp, 0x3f, sizeof(dp));
pos[0] = -1;
int i,lpos;
for (i = 0; i < n; ++i){
dp[lpos = (lower_bound(dp, dp + n, a[i]) - dp)] = a[i];
pos[lpos] = i; // *靠后打印
fa[i] = (lpos ? pos[lpos - 1] : -1);
}
n = lower_bound(dp, dp + n, INF) - dp;
for (i = pos[n - 1]; ~fa[i]; i = fa[i]) ans.push_back(a[i]);
ans.push_back(a[i]);
return n;
}
//非递减的LIS
int LISS(int n){
memset(dp, 0x3f, sizeof(dp));
pos[0] = -1;
int i,lpos;
for (i = 0; i < n; i++){
dp[lpos = (lower_bound(dp, dp + n, a[i],cmp) - dp)] = a[i]; //注意这里cmp
pos[lpos] = i; // *靠后打印
fa[i] = (lpos ? pos[lpos - 1] : -1);
}
n = lower_bound(dp, dp + n, INF) - dp;
for (i = pos[n - 1]; ~fa[i]; i = fa[i]) ans.push_back(a[i]);
ans.push_back(a[i]);
return n;
}
//单元最短路
const int maxn = 1e5 + 10;
vector<pair<int,int> > E[maxn];
int inq[maxn],n,m;
ll dis[maxn];
queue<int> q;
void spfa() {
for(int i = 0;i < maxn;i++) {
dis[i] = 2000000000;
inq[i] = 0;
}
dis[1] = 0;
q.push(1);
while(!q.empty()) {
int t = q.front();
q.pop();inq[t] = 0;
for(int i = 0;i < E[t].size();i++) {
int to = E[t][i].first;
ll di = E[t][i].second;
if(dis[to] > dis[t] + di) {
dis[to] = dis[t] + di;
if(!inq[to]) {
inq[to] = 1;
q.push(to);
}
}
}
}
}
//SLF优化:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j) < dist(i),则将j插入队首,否则插入队尾
void spfa() {
for (int i = 0; i < maxn; i++) dis[i] = INF;
deque<int> q;
dis[s] = 0;
q.push_back(s);
while (!q.empty()) {
int from = q.front();
q.pop_front();
inq[from] = 0;
for (int i = 0; i < E[from].size(); i++) {
int to = E[from][i].first;
int di = E[from][i].second;
if(dis[to] > dis[from] + di) {
dis[to] = dis[from] + di;
if(inq[to] == 0) {
inq[to] = 1;
if(q.size() && dis[to] < dis[from]) {
q.push_front(to);
} else {
q.push_back(to);
}
}
}
}
}
}
//线段树
const int MAXM=50000; //定义 MAXM 为线段最大长度
int a[MAXM+5],st[(MAXM<<2)+5]; // a 数组为 main 函数中读入的内容,st 数组为需要查询的数的信息(如和、最值等),树的空间大小为线段最大长度的四倍
void build(int o,int l,int r){ //传入的参数为 o:当前需要建立的结点;l:当前需要建立的左端点;r:当前需要建立的右端点
if(l==r)st[o]=a[l]; //当左端点等于右端点即建立叶子结点时,直接给数组信息赋值
else{
int m=l+((r-l)>>1); // m 为中间点,左儿子结点为 [l,m] ,右儿子结点为 [m+1,r];
build(o<<1,l,m); //构建左儿子结点
build((o<<1)|1,m+1,r); //构建右儿子结点
st[o]=st[o<<1]+st[(o<<1)|1]; //递归返回时用儿子结点更新父节点,此处可进行更新最大值、最小值、区间和等操作
}
} //在 main 函数中的语句 build(1,1,n);
//单点修改
void update(int o,int l,int r,int ind,int ans){ //o、l、r为当前更新到的结点、左右端点,ind为需要修改的叶子结点左端点,ans为需要修改成的值;
if(l==r){ //若当前更新点的左右端点相等即到叶子结点时,直接更新信息并返回
st[o]=ans;
return;
}
int m=l+((r-l)>>1);
if(ind<=m){ //若需要更新的叶子结点在当前结点的左儿子结点的范围内,则递归更新左儿子结点,否则更新右儿子结点
update(o<<1,l,m,ind,ans);
}
else{
update((o<<1)|1,m+1,r,ind,ans);
}
st[o]=max(st[o<<1],st[(o<<1)|1]);//递归回之后用儿子结点更新父节点(此处是区间最大值)
} //在main函数中的语句 update(1,1,n,ind,ans);
//对应单点修改的区间查询
int query(int o,int l,int r,int ql,int qr){ //ql、qr为需要查询的区间左右端点
if(ql>r||qr<l) return -1; //若当前结点和需要查找的区间不相交,则返回一个对于区间查询无关的值(如求和时返回0,求最大值时返回-1等)
if(ql<=l&&qr>=r) return st[o]; //若当前结点的区间被需要查询的区间覆盖,则返回当前结点的信息
int m=l+((r-l)>>1);
int p1=query(o<<1,l,m,ql,qr),p2=query((o<<1)|1,m+1,r,ql,qr); //p1为查询左儿子结点得到的信息,p2为查询右儿子结点得到的信息
return max(p1,p2); //综合两个儿子结点的信息并返回
}//main函数中的语句 printf("%d\n",query(1,1,n,a,b));
//区间加值
void pushup(int o){ //pushup函数,该函数本身是将当前结点用左右子节点的信息更新,此处求区间和,用于update中将结点信息传递完返回后更新父节点
st[o]=st[o<<1]+st[o<<1|1];
}
void pushdown(int o,int l,int r){ //pushdown函数,将o结点的信息传递到左右子节点上
if(add[o]){ //当父节点有更新信息时才向下传递信息
add[o<<1]+=add[o]; //左右儿子结点均加上父节点的更新值
add[o<<1|1]+=add[o];
int m=l+((r-l)>>1);
st[o<<1]+=add[o]*(m-l+1); //左右儿子结点均按照需要加的值总和更新结点信息
st[o<<1|1]+=add[o]*(r-m);
add[o]=0; //信息传递完之后就可以将父节点的更新信息删除
}
}
void update(int o,int l,int r,int ql,int qr,int addv){ //ql、qr为需要更新的区间左右端点,addv为需要增加的值
if(ql<=l&&qr>=r){ //与单点更新一样,当当前结点被需要更新的区间覆盖时
add[o]+=addv; //更新该结点的所需更新信息
st[o]+=addv*(r-l+1); //更新该结点信息
return; //根据lazy思想,由于不需要遍历到下层结点,因此不需要继续向下更新,直接返回
}
pushdown(o,l,r); //将当前结点的所需更新信息传递到下一层(其左右儿子结点)
int m=l+((r-l)>>1);
if(ql<=m)update(o<<1,l,m,ql,qr,addv); //当需更新区间在当前结点的左儿子结点内,则更新左儿子结点
if(qr>=m+1)update(o<<1|1,m+1,r,ql,qr,addv); //当需更新区间在当前结点的右儿子结点内,则更新右儿子结点
pushup(o); //递归回上层时一步一步更新回父节点
}
ll query(int o,int l,int r,int ql,int qr){ //ql、qr为需要查询的区间
if(ql<=l&&qr>=r) return st[o]; //若当前结点覆盖区间即为需要查询的区间,则直接返回当前结点的信息
pushdown(o,l,r); //将当前结点的更新信息传递给其左右子节点
int m=l+((r-l)>>1);
ll ans=0; //所需查询的结果
if(ql<=m)ans+=query(o<<1,l,m,ql,qr); //若所需查询的区间与当前结点的左子节点有交集,则结果加上查询其左子节点的结果
if(qr>=m+1)ans+=query(o<<1|1,m+1,r,ql,qr); //若所需查询的区间与当前结点的右子节点有交集,则结果加上查询其右子节点的结果
return ans;
}
//区间改值(其实只有pushdow函数和update中修改部分与区间加值不同)
void pushup(int o){
st[o]=st[o<<1]+st[o<<1|1];
}
void pushdown(int o,int l,int r){ //pushdown和区间加值不同,改值时修改结点信息只需要对修改后的信息求和即可,不用加上原信息
if(change[o]){
int c=change[o];
change[o<<1]=c;
change[o<<1|1]=c;
int m=l+((r-l)>>1);
st[o<<1]=(m-l+1)*c;
st[o<<1|1]=(r-m)*c;
change[o]=0;
}
}
void update(int o,int l,int r,int ql,int qr,int c){
if(ql<=l&&qr>=r){ //同样更新结点信息和区间加值不同
change[o]=c;
st[o]=(r-l+1)*c;
return;
}
pushdown(o,l,r);
int m=l+((r-l)>>1);
if(ql<=m)update(o<<1,l,m,ql,qr,c);
if(qr>=m+1)update(o<<1|1,m+1,r,ql,qr,c);
pushup(o);
}
int query(int o,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r) return st[o];
pushdown(o,l,r);
int m=l+((r-l)>>1);
int ans=0;
if(ql<=m)ans+=query(o<<1,l,m,ql,qr);
if(qr>=m+1)ans+=query(o<<1|1,m+1,r,ql,qr);
return ans;
}
//Trie树
const int maxn = 1e6 + 10;
char S[maxn];
struct Trie{
int next[26];
int cnt;
void init() {
cnt = 0;
memset(next, -1, sizeof next);
}
}T[maxn];
int le;
void Insert(string s) {
int p = 0;
for (int i = 0; i < s.size(); i++) {
int r = s[i] - 'a';
if(T[p].next[r] == -1) {
T[le].init();
T[p].next[r] = le++;
}
p = T[p].next[r];
T[p].cnt++;
}
}
void query(string s) {
int p = 0;
for (int i = 0; i < s.size(); i++) {
int r = s[i] - 'a';
if(T[p].next[r] == -1) {
cout<<0<<endl;
return ;
}
p = T[p].next[r];
}
cout<<T[p].cnt<<endl;
}
int main() {
ios_base::sync_with_stdio(0);
int n;cin>>n;
T[0].init();
le = 1;
for (int i = 0; i < n; i++) {
string s;cin>>s;
Insert(s);
}
int m;cin>>m;
while (m--) {
string s;cin>>s;
query(s);
}
return 0;
}
模板
最新推荐文章于 2022-09-06 22:40:36 发布