A. Uniform String(暴力)
题目连接:https://codeforces.com/contest/1092/problem/A
题目大意:T组数据,每组数据n,m,输出一个长为n的字符串,每个字符串中有m种字符,要让每个字符的出现频率最大,输出字符串。
分析:直接暴力,循环每次输出一排,然后在输出,可以保证,最少的字符出现次数最多。
AC:
int main()
{
int T;
while(cin>>T){
while(T--){
int n,k;
cin>>n>>k;
for(int i=0;i<n;++i){
int j=i%k;
cout<<char('a'+j);
}
cout<<endl;
}
}
}
B. Teams Forming(排序暴力)
题目链接:https://codeforces.com/contest/1092/problem/B
题目大意:给出一个数组,将这个数组种的元素两两配对,要求配对的两个元素值相等,+1可以使一个元素的值+1,问最少需要加多少,才可以配对成功。
思路:从小到大排序,然后前后必定是相差最少的。因为题目保证必定2*n,所以直接相加即可。(我又在想,如果不是2*n的话,组成小组,花费最小应该怎么解决。。)
AC:
int arr[MAXN];
int main()
{
int n;
while(cin>>n){
clean(arr,0);
for(int i=1;i<=n;++i)
cin>>arr[i];
sort(arr+1,arr+n+1);
ll ans=0;
for(int i=1;i<n;i+=2){
ans+=arr[i+1]-arr[i];
//cout<<ans<<endl;
}
cout<<ans<<endl;
}
}
C. Prefixes and Suffixes(思维,暴力)
题目链接:https://codeforces.com/contest/1092/problem/C
题目大意:一个n个元素的字符串,里面有n-1个前缀,n-1个后缀,我们已知这些前后缀,然后,跟据这些前后缀,组装成原本的字符串,然后再对每个字串,输出是前缀(P)||后缀(S)
思路:选区两个最长的字串,将他们拼接道一起,然后有两种拼接方式,对于每种拼接方式,遍历所有的子串,看是否所有的字串都被包含,如果都被包含,则确定这个串是原来的字符串。
AC:
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
//#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ˮӡ
//std::ios::sync_with_stdio(false);
// register
const int MAXN=2e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const double PI=acos(-1.0);
struct node{
char s[110];
int l;
}arr[MAXN];
char res[110];
string ans;
int n;
set<string> Set1,Set2;
multiset<string> Mul;
int judge(int a,int b){
Set1.clear();Set2.clear();Mul.clear();
clean(res,'\0');
for(int i=0;i<arr[a].l;++i)
res[i]=arr[a].s[i];
res[n-1]=arr[b].s[n-2];
string ans1="",ans2="";
for(int i=0;i<n-1;++i){
ans1+=res[i];
ans2=res[n-i-1]+ans2;
Set1.insert(ans1);
Set2.insert(ans2);
Mul.insert(ans1);
Mul.insert(ans2);
}
for(int i=1;i<=2*n-2;++i){
multiset<string>::iterator Find=Mul.find(arr[i].s);
if(Find==Mul.end())
return 0;
Mul.erase(Find);
}
set<string>::iterator s1,s2;
int vis[110]={0};
ans="";
for(int i=1;i<=2*n-2;++i){
s1=Set1.find(arr[i].s),s2=Set2.find(arr[i].s);
if(s1!=Set1.end()&&s2==Set2.end()){//��ǰ
ans+="P";
vis[arr[i].l]=1;
//cout<<"find1:"<<*s1<<endl;
}
else if(s1==Set1.end()&&s2!=Set2.end()){//�Ǻ�
ans+="S";
vis[arr[i].l]=2;
//cout<<"find2:"<<*s2<<endl;
}
else{
if(vis[arr[i].l]==1){//����ǰ
ans+="S";
}
else{
ans+="P";
if(vis[arr[i].l]==0)//û�г��ֹ�
vis[arr[i].l]=1;
}
}
}
//cout<<ans<<endl;
return 1;
}
int main(){
while(cin>>n){
int fir=0,sec=0;
for(int i=1;i<=2*n-2;++i){
cin>>arr[i].s;
arr[i].l=strlen(arr[i].s);
if(arr[i].l==n-1){
if(fir==0) fir=i;
else sec=i;
}
}
//cout<<"----------------------"<<endl;
if(judge(fir,sec)==0){//firΪǰ
judge(sec,fir);
}
cout<<ans<<endl;
}
}
D1. Great Vova Wall (Version 1)(思维,规律)
题目链接:https://codeforces.com/contest/1092/problem/D1
题目大意:给你n堆东西的高度,问最终能否使这n堆东西的高度一致,你可以使用1*2或2*1的小方块覆盖在上面。
思路:所有相邻的两个高度,都可以变成高度差<=1的高度,然后高度差1的永远也无法填上,因此,维护一个栈,每次看栈顶和输入元素高度差是否为奇数。奇数入栈,偶数出栈顶。
AC:
stack<int> st;
int main()
{
int n;
while(cin>>n){
while(st.size())
st.pop();
int h;
for(int i=1;i<=n;++i){
cin>>h;
if(st.size()==0)
st.push(h);
else{
if(st.top()%2==h%2){
st.pop();
}
else
st.push(h);
}
}
if(st.size()<=1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
D2. Great Vova Wall (Version 2)(思维,条件)
题目链接:https://codeforces.com/contest/1092/problem/D2
题目大意:D1的变形,不过不能用1*2的小方块了,只能用2*1的(横着的)
思路1:这样的话,就有了几种情况,即:1.该行为偶数2. 该行为奇数,但前面那行为偶数3.该行为奇数&&前面那行也为奇数,4.该行于前面那行的高度一样。
1的话,两行合并取高的(如果前面的较低,让前面的变高即可,平齐||+1),2.无法合并3.无法合并4.直接合并。维护一个栈即可,看最后栈中的元素还剩多少个。
思路2:D1的思路,加一些条件:显然,1.如果新加入的这个比栈顶元素还大的话,必定不可能抵消(能抵消的出栈了,能抵消意味着它的高度可以是任意的>=它本身)2.如果最后,栈中只有一个元素&&该元素>=所有的元素,则可以被抵消,若小于,则前面的不能与他抵消,不符合。
AC:
int arr[MAXN];
stack<int> st;
int main()
{
int n;
while(cin>>n){
clean(arr,0);
while(st.size())
st.pop();
int h,maxx=0,f=1;
for(int i=1;i<=n;++i){
cin>>h;
maxx=max(maxx,h);
if(st.size()==0){
st.push(h);
}
else{
if(st.top()==h){
st.pop();
}
else{
if(h>st.top())
f=0;
st.push(h);
}
}
}
if(f==0)
cout<<"NO"<<endl;
else if(st.size()==0)
cout<<"YES"<<endl;
else if(st.size()==1&&st.top()>=maxx)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
F. Tree with Maximum Cost(树根移动,思维)
题目链接:https://codeforces.com/contest/1092/problem/F
题目大意:给你一棵树,有一个答案:,来使得答案最大话。
思路:第一次DFS得出一棵树。然后第二次DFS得出树根向不同子节点偏移的值,取最大的即可。
ACCode:
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define Pair pair<int,int>
#define M_P(a,b) make_pair(a,b)
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
// register
const int MAXN=2e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
int a[MAXN];
ll Sum[MAXN];
vector<int> Mp[MAXN];
ll res,ans;
int n;
void DFS(int u,int fa,int deep=0){
res+=deep*1ll*a[u];
Sum[u]=a[u];
for(int i=0;i<Mp[u].size();++i){
if(Mp[u][i]==fa) continue;
DFS(Mp[u][i],u,deep+1);
Sum[u]+=Sum[Mp[u][i]];
}
}
void DFS2(int u,int fa){
ans=max(ans,res);
for(int i=0;i<Mp[u].size();++i){
if(Mp[u][i]==fa) continue;
res-=Sum[Mp[u][i]];
Sum[u]-=Sum[Mp[u][i]];
res+=Sum[u];
Sum[Mp[u][i]]+=Sum[u];
DFS2(Mp[u][i],u);
res-=Sum[u];
Sum[Mp[u][i]]-=Sum[u];
res+=Sum[Mp[u][i]];
Sum[u]+=Sum[Mp[u][i]];
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<n;++i){
int u,v;scanf("%d%d",&u,&v);
Mp[u].push_back(v);Mp[v].push_back(u);
}DFS(1,0);DFS2(1,0);
printf("%lld\n",ans);
}
/*
这个学校建筑结构体是奇怪的。
但是这个规则是只有一个相同的路线在两个教室。
现在,战斗在A教室和F教室之间打破。
作为支持F教室的员工,你必须去斗争在时间内帮助他们。
F教室知道可能每个教室都会攻击。
我们定义一个重要的学位,对于每个教室,
现在,问你发现一个教室x,在n个教室中,
作为休息有最小的F(x)=sigma(w[i]*Dis(x,i))(x教室和i教室之间的距离)
*/
//ll a[MAXN];//解法2
//ll Dis1[MAXN],Dis2[MAXN];//点的儿子对这个点的贡献
//ll Sum[MAXN];//该节点子节点的点权和
//vector<int> E[MAXN];
//int n;
//
//void DFS(int u,int fa){
// Sum[u]=a[u];//获得元素的值
// int len=E[u].size();
// for(int i=0;i<len;++i){//遍历邻接表
// if(E[u][i]==fa) continue;//避免回溯
// DFS(E[u][i],u);//深搜所有节点
// Sum[u]+=Sum[E[u][i]];//该节点的和 = 该节点+下一节点
// Dis1[u]+=Dis1[E[u][i]]+Sum[E[u][i]];//该节点的距离+=(下一节点的距离+下一节点的和)
// }
//}
//void DFS2(int u,int fa){
// if(u!=1){
// if(fa==1){//该节点是根节点的子节点
// Dis2[u]=Dis1[fa]-Dis1[u]-Sum[u];
// Dis2+=(Sum[fa]-Sum[u]);
// }
// else{//该节点不是根节点的子节点
// Dis2[u]=Dis2[fa];
// Dis2[u]+=(Sum[1]-Sum[fa]);
// Dis2[u]+=(Sum[fa]-Sum[u]);
// Dis2[u]+=(Dis1[fa]-Dis1[u]-Sum[u]);
// }
// }int len=E[u].size();
// for(int i=0;i<len;++i){
// if(E[u][i]==fa) continue;
// DFS2(E[u][i],u);
// }
//}
//void Show(int u,int fa){
// printf("u=%d Dis1[u]=%d Sum[u]=%d\n",u,Dis1[u],Sum[u]);
// int len=E[u].size();
// for(int i=0;i<len;++i){
// if(E[u][i]==fa) continue;
// Show(E[u][i],u);
// }
//}
//int main(){
// scanf("%d",&n);
// for(int i=1;i<=n;++i) scanf("%d",&a[i]);
// for(int i=1;i<n;++i){
// int u,v;scanf("%d%d",&u,&v);
// E[u].push_back(v);E[v].push_back(u);
// }DFS(1,0);Show(1,0);
// DFS2(1,0);
// ll ans=0;
// for(int i=1;i<=n;++i){
// ans=max(ans,(Dis1[i]+Dis2[i]));
// }printf("%lld\n",ans);
//}