CodeChef AMLEX Poetic word(网络流)

Poetic word

Dhinwaji is an acclaimed poet and likes to play with words and letters. He has bought some stickers where each sticker has a lower case english letter (a-z). The letters are indexed from 1 - 26 i.e. a has index 1, b has index 2 and so on. He has ai stickers with letter i on it. He needs to create a new word having exactly nletters. Being a programmer, Dhinwaji imposed another constraint: a letter with index j can only be placed at position i in the word if i % j = 0 i.e. i should be a multiple of j. Note that everything is 1-indexed. Note also that not all the stickers need to be used.

Dhinwaji wonders what is the lexicographically smallest word he can create that follows the above constraints. Since he is too busy writing poems, you have to help him find this word. Note that it is possible that there is no valid word of nletters that can be formed.

Input

  • The first line will have a number T indicating the number of test cases. T lines follow.
  • The first line of each test case will have one integer, n, denoting the required length of the new word.
  • The second line of each test case will have 26 space separated integers a1a2, ..., a26

Output

  • For each test case, print one line containing the lexicographically smallest word which satisfies the conditions. If no such word is possible, print "#rekt" without the quotes.

Constraints

  • 1 ≤ T ≤ 5
  • 1 ≤ n ≤ 200
  • 0 ≤ ai ≤ n

Example

Input:
3
3
1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  
6
3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  
10
1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  

Output:
abc
aacbab
#rekt

Explanation

Testcase 1: There is 1 sticker with a, b and c each. "abc" is the only valid word possible

Testcase 2: Some valid words are "abcaab", "abcbaa", "ababac" etc. The lexicographically smallest among them is aacbab

Testcase 3: There are a total of 3 letters so a word with 10 letters cannot be formed

题目大意:给你26个字母每一个的个数,让你造出一个长度为n的字符串,且字符串的字典序最小

先判断不存在的情况,假如当前我有的这些字母用来跑网络流都跑不出一个答案,那肯定是不行的。如果可以的话,再不济也就是这一个字符串,也就是有结果的。

如果存在的话,我们就枚举每个位置去放,对于一个位置,枚举26个字母,然后判断是否有可行流,就假设当前这个位置放了字符,那只需判断剩下的位置,对于剩下的位置,每个位置与可以放的字母连一条边,容量为1,源点与每个字母连一条容量为这个字母的个数的边,然后剩下的位置都与汇点连一条容量为1的边,跑一遍最大流,看最终的答案是否等于剩下的位置数,如果是的话,这个位置放这个字母就是可行的。不是的话,就“回溯”

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<queue>
using namespace std;
const int maxn=1010;
const int maxm=10010;
const int inf=0x3f3f3f3f;
struct Node
{
    int to;
    int capa;
    int next;
}edge[maxm];
int n;
int source,sink;
int cnt;
int head[maxn];
bool vis[maxn];
int dep[maxn];
int num[30];
void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
    return;
}
void add(int u,int v,int capa)
{
    edge[cnt].to=v;
    edge[cnt].capa=capa;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].to=u;
    edge[cnt].capa=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
    return;
}
bool bfs()
{
    queue<int> que;
    que.push(source);
    memset(dep,-1,sizeof(dep));
    dep[source]=0;
    while(!que.empty())
    {
        int node=que.front();
        que.pop();
        for(int i=head[node];~i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(edge[i].capa>0&&dep[v]==-1)
            {
                dep[v]=dep[node]+1;
                if(v==sink) return true;
                que.push(v);
            }
        }
    }
    return dep[sink]!=-1;
}
int dfs(int node,int minn)
{
    if(node==sink||minn==0)
    {
        return minn;
    }
    int r=0;
    for(int i=head[node];~i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(dep[v]==dep[node]+1&&edge[i].capa>0)
        {
            int tmp=dfs(v,min(edge[i].capa,minn));
            if(tmp>0)
            {
                edge[i].capa-=tmp;
                edge[i^1].capa+=tmp;
                r+=tmp;
                minn-=tmp;
                if(!minn) break;
            }
        }
    }
    if(!r) dep[node]=-1;
    return r;
}
int dinic()
{
    int maxflow=0;
    while(bfs())
    {
        maxflow+=dfs(source,inf);
    }
    return maxflow;
}
bool judge(int idx)
{
	init();
	for(int i=1;i<=26;i++)
	{
		for(int j=idx+1;j<=n;j++)
		{
			if(j%i==0)
			{
				add(i,j+26,1);
			}
		}
		add(source,i,num[i]);
	}
	for(int i=idx+1;i<=n;i++)
	{
		add(i+26,sink,1);
	}
	return dinic()==n-idx;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int test;
	scanf("%d",&test);
	while(test--)
	{
		source=0;
		sink=300;
		scanf("%d",&n);
		for(int i=1;i<=26;i++)
		{
			scanf("%d",&num[i]);
		}
		if(!judge(0))
		{
			puts("#rekt");
		}
		else
		{
			string ans="";
			for(int i=1;i<=n;i++)
			{
				for(int j=1;j<=26;j++)
				{
					if(num[j]>0&&i%j==0)
					{
						num[j]--;
						if(judge(i))
						{
							ans+='a'+j-1;
							break;
						}
						num[j]++;
					}
				}
			}
			cout<<ans<<endl;
		}
	}
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值