宿舍熄灯导致提前跑路(不然应该可以多做一道题的)
说起来这比赛的题目应该分为什么类呢?感觉有点像脑筋急转弯(bushi)。
题意:给出n个由小写英文字母组成的字符串,一次操作可以将一个字符串中的任意一个字符移动到另一个字符串的任意一个位置,可以进行任意次操作。问是否能够将这n个字符串变为n个相同的字符串。
思路:显然只要这n个字符串中的每个字符都出现了n的倍数次,就能够变出n个相同的字符串。
因此使用cnt数组记录每个小写英文字母出现的总次数,如果cnt都能够被n整除,则输出YES,否则输出NO。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int cnt[30]; char s[1005]; int main() { int T,i,j,n,flag,len; scanf("%d",&T); while (T--) { memset(cnt,0,sizeof(cnt)); flag=0; scanf("%d",&n); for (j=1;j<=n;j++) { scanf("%s",s); len=strlen(s); for (i=0;i<len;i++) cnt[s[i]-'a']++; } for (i=0;i<26;i++) { if (cnt[i]%n!=0) { flag=1; break; } } if (flag) printf("NO "); else printf("YES "); } return 0; }
题意:给出一个含有n个元素的序列a,你需要依次进行以下两个步骤:
1、不花费任何费用,将原序列重新排序
2、(这个操作可以进行任意次)花费费用1,选择任意i,将a[i]变为a[i]-1或a[i]+1。
求出将原序列变为等比数列(对于任意i有a[i]=ci其中c为正整数)的最小花费
思路:由于幂序列一定不是单调递减序列,对于第一个步骤,将a从小到大排序。
然后就可以直接枚举c找最小花费了。
因为等比数列递增得很快,可以凭借直觉(bushi)发现c不会太大,直接枚举不会超时。
只要设置一个上界(我设置了1e14,这是n=1e5,a[i]=1e9,c=1时的大概花费),在等比数列的某一项到达上界时退出就行了。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; ll ans,re,now,a[100005]; const long long lim=1e14; int main() { int T,i,j,n,flag; scanf("%d",&n); for (i=0;i<n;i++) scanf("%lld",&a[i]); sort(a,a+n); ans=-1; for (i=0;i<=100000;i++) { now=1;flag=0; re=0; for (j=0;j<n;j++) { if (now>lim) { flag=1; break; } re+=abs(now-a[j]); now=now*i; } if (flag) continue; if (ans==-1 || re<ans) ans=re; } printf("%lld ",ans); return 0; }
题意:给出一个序列a,每次操作能够将其中一个长度为len的区间中的每一项加上一个len的倍数(这些数不一定相同,可以是负数)。可以证明只要三个操作就能将这个序列变为0序列,要求输出一组具体的三次操作。
思路:将前n-1项都加上a[i]*(n-1),第n项加上a[n]*(n-1),最后将所有项减去a[i]*n即可。记得特判n==1。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; ll a[100005]; int main() { int i,n; scanf("%d",&n); for (i=1;i<=n;i++) scanf("%lld",&a[i]); if (n==1) { printf("1 1 0 "); printf("1 1 0 "); printf("1 1 %lld",-a[1]); return 0; } printf("1 %d ",n-1); for (i=1;i<=n-1;i++) printf("%lld ",a[i]*(n-1)); printf(" "); printf("%d %d ",n,n); printf("%lld ",a[n]*(n-1)); printf("1 %d ",n); for (i=1;i<=n;i++) printf("%lld ",-a[i]*n); return 0; }
题意:有n堆石头,T和NL轮流从某一堆石头中取出一个石头,并且不能够从对方上一轮取石头的那一堆石头中取。T先手,当有人无法取出石头时则此人输,问谁能够赢。
思路:当前玩家应当会选择当前局面中石头数最多的那堆石头取,因为只要取这堆石头,对方就不能取这堆石头,于是更可能获得胜利。
于是,首先,如果有一堆石头比其他所有石头都要多,则T 必胜(这堆石头会一直比其他石头堆中的石头多)。
然后,如果石头总数为奇数,则T胜,否则NL胜。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxn 105 using namespace std; typedef long long ll; int a[maxn],cnt,sum; int main() { int i,T,n,flag; scanf("%d",&T); while (T--) { scanf("%d",&n); sum=0; cnt=0; flag=0; for (i=1;i<=n;i++) { scanf("%d",&a[i]); if (a[i]&1) cnt++; sum+=a[i]; } for (i=1;i<=n;i++) if (a[i]>sum-a[i]) { flag=1;break; } if (flag) printf("T "); else { if (cnt&1) printf("T "); else printf("HL "); } } return 0; }