2距离考完试比较近而且题比较难,所以就先写2了。
在这之前还是要先总结一下自己的所作所为,寒假不做题,上学期又一直浪,基础本来就不好,导致成绩急速下滑。这次划线我在省赛之下,所以,自己心里有点C数。
再说考试心态,紧张个P,动不动就浮躁,看个题看不完就看别的,老老实实正着看题!
A - Watching TV
Gym - 101498A题目大意:熊孩子不学习,他爸怒了,让他以后只能看一个台(频率),你要帮助熊孩子选择节目尽可能多的台(频率)
题目不难,读完题就能写代码,题目的坑点在于
It is possible that two different channels have the same name and frequency.
这句话,这句话的意思是,如果一个频率有两个相同名称的节目,那么也算作两个节目。
也就是说去重是多余的。加了去重可能就Wr了.
AC
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
using namespace std;
typedef unsigned long long ll;
const int SIZE = 100010;
//map <int, map<string,bool> > vis;
map <int,int> countt;
string s;
int tmp,maxx,ans;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
countt.clear();
maxx = 0;
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
{
// s.clear();
cin>>s;
scanf("%d",&tmp);
// if(!vis[tmp][s])
// {
countt[tmp] ++;
// vis[tmp][s] = 1;
// }
if(countt[tmp] > maxx)
{
maxx = countt[tmp];
ans = tmp;
}
if(countt[tmp] == maxx) ans = min(ans,tmp);
}
printf("%d\n",ans);
}
return 0;
}
/*
3
4
mbcone 12015
mbctwo 12015
mbcone 12015
mbcthree 12014
2
channelone 11112
channelyou 21112
1
watchme 12345
*/
B - Longest Prefix
Gym - 101498B题目大意:给你两个字符串A,B,你可以对B进行一系列操作或者不操作,让A,B的公共前缀长度最长,求这个最长长度。
水题之2,A不动,B可以任意操作,所以只需要把B中各个字母的个数记下来,扫一遍A,发现一个字母c在B中有的就count[c]--;直到发现对于A中的某个字母count[c] == 0就break,记录下这个最长长度。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
using namespace std;
typedef unsigned long long ll;
const int SIZE = 100010;
int countb[233];
char s1[SIZE],s2[SIZE];
int main()
{
int t;
cin>>t;
for(int j = 1;j <= t;j ++)
{
memset(countb,0,sizeof(countb));
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
cin>>s1>>s2;
int l1 = strlen(s1);
int l2 = strlen(s2);
for(int i = 0;i < l2;i ++) countb[s2[i]-'a'+1] ++;
int sum = 0;
for(int i = 0;i < l1;i ++)
{
if(countb[s1[i]-'a'+1])
{
sum ++;
countb[s1[i]-'a'+1] --;
}
else if(!countb[s1[i]-'a'+1]) break;
}
cout<<sum<<endl;
}
return 0;
}
/*
aaaabbbccd
abbcccdddd
3
hello hey
here there
you me
*/
C - Super Subarray
Gym - 101498G题目大意:给定一个序列,求超级子序列的个数
超级子序列:序列中所有元素的和 % 每个元素都为0;
思路:考场上各种脑子瓦特。 这个数膜每个元素都是0,那么这个数肯定是这些元素公共最小公倍数(lcm)的倍数。而和的问题也很好解决,用前缀和可以做到O1查询。所以这个题我们需要做的就是枚举所有的子区间,复杂度是n^2.再看看数据范围,n上限2000,T是100 这样算下来复杂度是400000000,肯定是要TLE的。这时候考虑一下玄学优化,这里考虑 如果公共lcm大于n*1e9,那么无论哪些数的和加起来都不会是它的倍数,因为所有数加起来最大也就是n*1e9.这样我们就加一个类似于剪枝的操作就能过了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
using namespace std;
typedef unsigned long long ll;
const int SIZE = 2010;
int t,n;
ll sum,lcsum,num[SIZE],countt,maxx;
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a%b);}
ll lcm(ll a,ll b){return a*b/gcd(a,b);}
int main()
{
scanf("%d",&t);
while(t--)
{
countt = 0;
scanf("%d",&n);
maxx = (ll)(n) * (ll)(1e9);
for(int i = 1;i <= n;i ++) scanf("%lld",&num[i]);
for(int i = 1;i <= n;i ++)
{
sum = 0;
lcsum = num[i];
for(int j = i;j <= n;j ++)
{
sum += num[j];
lcsum = lcm(lcsum,num[j]);
if(sum % lcsum == 0) countt ++;
if(lcsum > maxx) break;
}
}
printf("%lld\n",countt);
}
return 0;
}
D - Two Subarrays
Gym - 101498KE - Restaurant
UVALive - 4851D 看懂了不太会做。。 E没看懂题。。
F - ENimEN
UVA - 11892题目大意:原来的NIM游戏太无聊,这俩人玩出了花样,当前人拿完石子之后,如果当前堆仍有石子,那么下一个人必须从这堆里拿。
一直不太懂NIM游戏之类的博弈论问题。。这个也不例外。。 看了题解之后明白了,到自己做却就是不会推。。所以要补一下了。。。。
对于所有情况,当且仅当堆的个数为偶数且所有堆石子都为1个时piloop(后手)才能赢。
如果都是1的情况,那么奇数先手赢,偶数后手赢.
在不都是1的情况下,如果1的个数为奇数,其他堆都拿到只剩1个,那么后手只能拿完这堆,然后最终剩下奇数个1;
如果1的个数是偶数个,那么同样按照上述方法,不过当当前堆是最后一个不为1的堆时直接拿完。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
const int SIZE = 100010;
int t;
int main()
{
scanf("%d",&t);
while(t--)
{
int tmp,n,count = 0;
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
{
scanf("%d",&tmp);
if(tmp != 1) count = -1;
else if(count != -1) count ++;
}
if(count != -1 && count % 2 == 0) puts("piloop");
else puts("poopi");
}
return 0;
}
G - Neon Sign
UVALive - 5846题目大意:给定N边型(N >= 3),任意两点之间有连线,这些连线有两种颜色,输入每条线的颜色,问最终同色三角形的个数。
考试的时候没读懂题,其实是被那个图吓到了。
考完试再回顾这个题,一开始当然是想邻接矩阵存颜色,对每个点搜同色的边的组合,然后看第三条边颜色是否相同,复杂度N^3*T 肯定TLE。
其实这个题用了一个容斥原理思想。你想求同色三角形个数,不好求,能不能求总三角形减去非同色三角形。这个时候就应该想非同色三角形好不好求了。对于一个点,如果它直连两条边颜色不同,那么它肯定是非同色三角形。这样每个点直接red[i]*blue[i]就是非同色三角形个数了。 同时 对于每个非同色三角形,有两个顶点在计算时会把这个三角形计算进去,另一个点看来它直连两边是同色的(只有两色,要么是aab要么是abb)。所以这个sum要除以2。而总三角形个数是C(n,3),即代码里写的公式。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
const int SIZE = 100010;
int red[2333],blue[2333],n,t,tmp;
int main()
{
scanf("%d",&t);
while(t--)
{
memset(red,0,sizeof(red));
memset(blue,0,sizeof(blue));
scanf("%d",&n);
for(int i = 1;i < n;i ++)
{
for(ll j = i+1;j <= n;j ++)
{
scanf("%d",&tmp);
if(tmp == 0)
{
red[i] ++;
red[j] ++;
}
else
{
blue[i] ++;
blue[j] ++;
}
}
}
int sum = 0;
for(int i = 1;i <= n;i ++) sum += red[i]*blue[i];
int ans = n*(n-1)*(n-2)/6-sum/2;
printf("%d\n",ans);
}
return 0;
}
H - A Bit Fun
HDU - 4737题目大意:给定一个序列,以及m,求序列中满足(a i|a i+1|a i+2| ... | a j )< m 的子序列的个数。
这个题N<=100000,显而易见N^2算法过不了,但实际上N^2居然过了。。数据比较水。。随意了
N^2算法:对于每组数据,同样枚举所有子序列,但是这个枚举有边界,即当当前的 或和 大于或等于m时再往后找就没有意义了,因为或运算得到的结果一定大于当前数。所以按照这个方法枚举所有子序列计算结果即可。
同时想卡这个算法也很容易,只需要一组数据:
1
100000 2
1 1 1 1 1 1 1 …… 1
所以数据水 不要在意了~
I - GCD Guessing Game
UVALive - 5916这题有歧义,不管了。