A题题目链接
题意:给一个数组请问这个数组是否符合先升序后降序,是输出Yes否则输出No。
思路:直接遍历数组判断
C++代码:
#include
using namespace std;
const int maxn = 100010;
int n,a[maxn];
int main()
{
int T; scanf ( "%d" , &T );
while ( T-- )
{
scanf ( "%d" , &n );
for ( int i=1 ; i<=n ; i++ )
scanf ( "%d" , &a[i] );
bool ok1 = false,ok2 = true;
if ( a[1]>=a[2] )
{
ok1 = false;
ok2 = true;
}
else
{
for ( int i=3 ; i<=n ; i++ )
{
if ( a[i]==a[i-1] )
{
ok1 = false;
ok2 = true;
break;
}
else if ( a[i]a[i-1] )
{
if ( ok1==true )
ok2 = false;
}
}
}
if ( ok1&&ok2 )
printf ( "Yes\n" );
else
printf ( "No\n" );
}
return 0;
}
B题题目链接
题意:给两个数组D和S,可以给数组D的每一位加上K,请问加上K后D数组和S数组对应位置数字相同的最大值是多少。
思路:直接做差,然后求做差后得到的结果数组的众数。
C++代码:
#include
using namespace std;
const int maxn = 100010;
int n,a[maxn],b[maxn],c[maxn];
int main()
{
int T; scanf ( "%d" , &T );
while ( T-- )
{
scanf ( "%d" , &n );
for ( int i=1 ; i<=n ; i++ )
scanf ( "%d" , &a[i] );
for ( int i=1 ; i<=n ; i++ )
scanf ( "%d" , &b[i] );
for ( int i=1 ; i<=n ; i++ )
c[i] = b[i]-a[i];
sort ( c+1 , c+n+1 );
int ans = 0;
for ( int i=1 ; i<=n ; i++ )
{
int l=i,r=i;
while ( r+1<=n&&c[r+1]==c[l] ) r++;
ans = max ( ans , r-l+1 );
i=r;
}
printf ( "%d\n" , ans );
}
return 0;
}
C题题目链接
题目背景:将印有数字1-12的牌各4张均分到12堆,每堆各4张。从第一堆开始取牌,取到数字几就到第几堆继续取牌。直到想去某堆取牌但是那堆牌却为空停止。
题意:在保证游戏未结束的情况下,给出前n步操作 ,要求输出当游戏结束时各堆为空的概率为多少(分数表示)。
思路:首先有个结论:最终游戏结束一定是想去第一堆取牌而第一堆没牌可取。(证明:每种数字牌只有4张,且除了第一堆外其他堆都有4张牌,即除了第一堆外其他堆都有足够的牌提供给那4次取牌。)假设进行n次抽牌后1剩余x张,2剩余y张,那么2被抽空的概率为x/(x+y)。(证明:如果将每张牌都看成独立的,那么每张牌被抽的概率相同。那么y张牌先于x张牌抽空的概率为x/(x+y))
C++代码:
#include
using namespace std;
int n,a[110];
char str[10];
int GCD( int a , int b )
{
if ( b==0 ) return a;
else return GCD( b , a%b );
}
int main()
{
int T; scanf ( "%d" , &T );
while ( T-- )
{
scanf ( "%d" , &n );
for ( int i=1 ; i<=12 ; i++ )
a[i] = 4;
for ( int i=1 ; i<=n ; i++ )
{
scanf ( "%s" , str );
if ( str[0]=='A' ) a[1]--;
else if ( str[0]=='J' ) a[11]--;
else if ( str[0]=='Q' ) a[12]--;
else if ( str[1]!='\0' ) a[10]--;
else a[str[0]-'0']--;
}
printf( "1" );
for ( int i=2 ; i<=12 ; i++ )
{
int x = a[1];
int y = a[1]+a[i];
if ( x==y ) printf( " 1" );
else if ( x==0 ) printf ( " 0" );
else
{
int gcd = GCD( x , y );
printf( " %d/%d" , x/gcd , y/gcd );
}
}
printf( "\n" );
}
return 0;
}
D题题目链接
题意:给一个仅包含左右括号且长度为n的字符串,每个字符有对应的权值。可以通过交换相邻的左右括号来获得权值乘积的分数,求最终可以获得的分数最大值。
思路:首先有个结论:对于一个左括号它可以和后面的所有右括号进行交换。于是乎就可以通过DP求解该问题了dp[i][j]表示在i这个位置的左括号匹配大于等于j个右括号可以得到的最大值。
C++代码:
#include
using namespace std;
typedef long long LL;
const int maxn = 1010;
int n;
char s[maxn];
LL a[maxn];
LL b[maxn];
LL dp[maxn][maxn];
int main()
{
int T; scanf ( "%d" , &T );
while ( T-- )
{
scanf ( "%d%s" , &n , s );
for ( int i=0 ; i=0 ; i-- )
{
if ( s[i]=='(' )
{
for ( int j=r-1 ; j>i ; j-- )
b[q++] = a[j];
dp[i][0] = dp[r][0];
LL tmp = 0;
for ( int k=1,j=q-1 ; k<=q ; k++,j-- )
{
tmp = tmp + a[i]*b[j];
dp[i][k] = tmp + dp[r][max(0,(k-(r-i-1)))];
}
for ( int k=q-1 ; k>=0 ; k-- )
dp[i][k] = max ( dp[i][k] , dp[i][k+1] );
r = i;
ans = max ( ans , dp[i][0] );
}
}
printf ( "%lld\n" , ans );
}
return 0;
}
E题题目链接
题意:有一个长度为n的序列f[],f[i]表示以第i个数为结尾的最长上升序列长度为f[i]。还给出了各个位置上的数据范围l[i],r[i]要求该位置上的数应该在此范围内。求任意一个可行解。
思路:发现题目中有不等式可用,所以我们采用差分约束来解决此题。定义dis[]数组表示该点的最终答案,即原序列。以0为原点,于是乎会有以下不等式产生。dis[i]-dis[0]<=r[i],dis[i]-dis[0]>=l[i],此外因为题目给的数据范围不尽相同,所以还需要以下不等式dis[last[f[i]]-dis[i]>=0,dis[last[f[i]+1]]-dis[i]>=1。通过以上不等式建图spfa最短路,即可得到答案。
C++代码:
#include
using namespace std;
const int maxn = 100010;
const int maxm = 500010;
const int inf = 0x7FFFFFFF;
int n,x,last[maxn],tol,head[maxn];
struct edge
{
int to,cost,next;
}es[maxm];
void init()
{
tol = 0; memset ( head , -1 , sizeof(head) );
}
void addedge( int u , int v , int w )
{
es[tol].to = v;
es[tol].cost = w;
es[tol].next = head[u];
head[u] = tol++;
}
int dis[maxn];
int vis[maxn];
void spfa()
{
for ( int i=1 ; i<=n ; i++ )
dis[i] = inf,vis[i] = 0;
queueQ;
Q.push(0);
vis[0] = 1;
dis[0] = 0;
while ( !Q.empty() )
{
int u = Q.front();
Q.pop();
vis[u] = 0;
for ( int i=head[u] ; i!=-1 ; i=es[i].next )
{
int v = es[i].to,w = es[i].cost;
if ( dis[v]>dis[u]+w )
{
dis[v] = dis[u]+w;
if ( !vis[v] )
{
vis[v] = 1;
Q.push(v);
}
}
}
}
}
int main()
{
int T; scanf ( "%d" , &T );
while ( T-- )
{
init(); scanf ( "%d" , &n );
memset ( last , 0 , sizeof(last) );
for ( int i=1 ; i<=n ; i++ )
{
scanf ( "%d" , &x );
if ( last[x] )
addedge( last[x] , i , 0 );
if ( last[x-1] )
addedge( i , last[x-1] , -1 );
last[x] = i;
}
for ( int i=1 ; i<=n ; i++ )
{
int l,r; scanf ( "%d%d" , &l , &r );
addedge( 0 , i , r );
addedge( i , 0 , -l );
}
spfa();
for ( int i=1 ; i<=n ; i++ )
{
if ( i!=1 ) printf ( " " );
printf ( "%d" , dis[i] );
}
printf ( "\n" );
}
return 0;
}
F题题目连接
题意:对题目所给公式进行求和并对1e9进行取模。
思路:对ai进行排序,然后由于底数最大不超过30所以考虑预处理ai/底数的结果并进行前缀和求和,然后对于询问给定p不断规定左右界进行二分,然后利用前缀和快速求解。
C++代码:
#include
using namespace std;
const int maxn = 500010;
const int mod = 1e9;
int n,m;
int a[maxn];
int b[35][maxn];
int main()
{
int T; scanf ( "%d" , &T );
while ( T-- )
{
scanf ( "%d%d" , &n , &m );
for ( int i=1 ; i<=n ; i++ )
scanf ( "%d" , &a[i] );
sort ( a+1 , a+n+1 );
for ( int i=1 ; i<=30 ; i++ )
{
b[i][0] = 0;
for ( int j=1 ; j<=n ; j++ )
{
b[i][j] = a[j]/i;
b[i][j] = ( b[i][j]+b[i][j-1] )%mod;
}
}
int ans = 0;
for ( int i=1 ; i<=m ; i++ )
{
int x; scanf ( "%d" , &x );
int L=1,R=x,sum=0,t=1;
while ( 1 )
{
int l = upper_bound( a+1 , a+n+1 , L )-a;
int r = upper_bound( a+1 , a+n+1 , R )-a;
sum = ( sum+(b[t][r-1]-b[t][l-1]) )%mod;
if ( a[n]/L
G题题目链接
题意:
定义两个非空字符串x,y和另外一个非空字符串z,若xz==zy,则称z是符合要求的字符串
给两个字符串s,t,长度分别为n和m,有q组询问每次询问给两个整数x,y,求符合sx,sx+1,。。。,sx+m-1和t要求的且长度不超过y的字符串z的个数
思路:
C++代码:
#include
using namespace std;
typedef long long LL;
const int maxn = 100010;
const int mod1 = 1e9+7;
const int mod2 = 1e9+9;
const int base1 = 131;
const int base2 = 233;
LL p1[maxn],p2[maxn];
LL Hash1[maxn];
LL Hash2[maxn];
int n,m,q,Next[maxn];
char a[maxn],b[maxn];
map,int>mp;
pair GetHash( int l , int r )
{
LL h1 = ( Hash1[r]-Hash1[l-1]*p1[m]%mod1+mod1 )%mod1;
LL h2 = ( Hash2[r]-Hash2[l-1]*p2[m]%mod2+mod2 )%mod2;
return make_pair( h1 , h2 );
}
int main()
{
p1[0] = 1;
p2[0] = 1;
for ( int i=1 ; ih;
for ( int i=1 ; i<=m ; i++ )
{
LL h1 = ( (h.first*base1 )%mod1+(LL)b[i] )%mod1;
LL h2 = ( (h.second*base2)%mod2+(LL)b[i] )%mod2;
h = make_pair( h1 , h2 );
}
int cnt = 0;
mp.clear();
for ( int i=1 ; i<=m ; i++ )
{
LL h1 = ( (h.first*base1 )%mod1+(LL)b[i] )%mod1;
LL h2 = ( (h.second*base2)%mod2+(LL)b[i] )%mod2;
h = make_pair( (h1-(LL)b[i]*p1[m]%mod1+mod1)%mod1 , (h2-(LL)b[i]*p2[m]%mod2+mod2)%mod2 );
if ( !mp[h] ) mp[h] = i;
}
while( q-- )
{
int x; LL y;
scanf ( "%d%lld" , &x , &y );
h = GetHash( x , x+m-1 );
if ( !mp[h] )
printf ( "0\n" );
else
printf ( "%lld\n" , (y-mp[h]+loop)/loop );
}
}
return 0;
}
H题题目链接
题意:
思路:
C++代码:
#include
using namespace std;
const int maxn = 1010;
typedef long long LL;
int tol,head[maxn];
struct edge
{
int to,next; LL cost;
}es[maxn];
LL sizes[maxn];
LL indeg[maxn];
LL dis[maxn];
LL dp[maxn][2];
void init()
{
tol = 0;
memset ( head , -1 , sizeof(head) );
memset ( sizes , 0 , sizeof(sizes) );
memset ( indeg , 0 , sizeof(indeg) );
memset ( dis , 0 , sizeof(dis) );
memset ( dp , 0 , sizeof(dp) );
}
void addedge( int u , int v , int w )
{
es[tol].to = v;
es[tol].cost = w;
es[tol].next = head[u];
head[u] = tol++;
}
void dfs( int u , int f )
{
if ( indeg[u]<=1 )
sizes[u] = 1;
else
sizes[u] = 0;
LL cnt = 0;
for ( int i=head[u] ; i!=-1 ; i=es[i].next )
{
int v = es[i].to; LL w = es[i].cost;
if ( v==f ) continue;
dis[v] = dis[u]+w;
dfs( v , u );
LL val;
sizes[u] += sizes[v];
if ( dis[v]+dp[v][0]
I题题目链接
题意:4n-4个点,从0开始编号,从(0,0)按逆时针开始逆时针放置,现在要求连接n条直线(n条直线都至少过两点并且不能平行于x轴和y轴),使得n条直线的交点尽量的多。
思路:先连接(0,n),(1,n+1)...(n-2,2*n-2)这n-1条直线,这n-1条直线一定两两相交且斜率不想等,故任意两个交点一定不重合。最后第n条直线,只需非对角线且斜率的绝对值与之前n-1条直线都不相等即可,比如连接(n-1,3*n-2)或(n-1,3*n-4)。特别的,当n==2时需要特判。
C++代码:
#include
using namespace std;
int main()
{
int T; scanf( "%d" , &T );
while ( T-- )
{
int n; scanf( "%d" , &n );
if ( n==2 )
printf( "0 2 1 3\n" );
else
{
for ( int i=0 ; i
J题题目链接
题意:一个长度为n的01串,0表示女生,1表示男生,现在要求将这些女生和男生分到四个组里面分别为G1,G2,G3,G4,其中G1,G2只能为女生G3,G4只能为男生,要求G1+G3的权值等于G2+G4的权值。第i个位置上的人拥有i点权值,输出任意满足要求的解。若无解则输出-1。
思路:首先可以简单的知道只有在n%4==0或n%4==3的情况下,才可能有解。
1.对于偶数情况,即n%4==0的情况:我们只要1,n,3,n-2,。。。分到一组,其余分给另一组即可。
2.对于奇数情况,即n%4==3的情况:我们先将1,n/2分给第一组,n/2+1分给另外一组,其余按偶数情况分开即可。
C++代码:
#include
using namespace std;
const int maxn = 100010;
char s[maxn];
int main()
{
int T; scanf ( "%d" , &T );
while ( T-- )
{
int n; scanf ( "%d%s" , &n , &s );
if ( n%4==3 )
{
int m = n/2;
if ( s[0]=='0' )
printf( "1" );
else
printf( "3" );
for ( int i=1,j=0 ; i
K题题目链接
题意:给出n块不同的麻将,有四种不同种类分别是C:万,B:条,D:筒,W:白板。优先级顺序为C
思路:因为题目已经保证初始局面一定合法且至少有一种满足置换,所以我们可以先通过判断是否有逆序情况来判断是不是只有唯一解。若发现数据无逆序,我们下一步去寻找是否有白板。若无白板则答案为3*m-n+1即没出现过的牌或者头张牌,若有白板则考虑去寻找白板的位置根据白板位置不同有如下情况:
白板在开头:答案为第二块牌的大小-1
白板夹在两牌中间:答案为前后两牌差的大小-1
白板在结尾:答案为3*m-倒数第二块牌的大小
最后注意白板在第二位置上时,答案需要+1
C++代码:
#include
using namespace std;
const int maxn = 100010;
int n,m,x,w;
int a[maxn];
bool ok()
{
w = 0;
for ( int i=1 ; i
L题题目链
题意:有n个字符串,每个字符串有对应的权值x,在其中选取m个字符串,要求ans通过计算公式for(i=0;i 思路:贪心,取前m个字符串。 C++代码: M题题目链接 题意:有n个数字和一个整数b,问这n个数字中是否存在一个数字(xi+b)%7==0,有输出Yes,无则输出No。 思路:直接判断。 C++代码:#include
#include