博采众长,共同进步
注:按照以往经验,难度评价以ACM区域赛作为标准
考点:送气球题,阅读筛选信息
思路:根据题目信息,疯狂if…else即可
#include
#include
using namespace std;
int main(){
int a1,b1,c1,a2,b2,c2;
cin>>a1>>b1>>c1>>a2>>b2>>c2;
if(a1>a2)
cout<<1<b2)
cout<<2<c2)
cout<<2<
考点:经典题,贪心
#include
using namespace std;
#include //memset
#define INF 0x3f3f3f3f
const int SZ=102;
int d[SZ][SZ];
int s[SZ];
//最大子段和
int MaxArray(int a[],int n)
{
int m=-INF;
int tmp=-1;
for(int i=0;i0)
tmp+=a[i];
else
tmp=a[i];
if(tmp>m)
m=tmp;
}
return m;
}
int main()
{
int i,j,k,n;
cin>>n;
for(i=0;i>d[i][j];
int ans=-INF,tmp;
for(i=0;ians)
ans=tmp;
}
}
cout<
思路:思维题,以m为中心统计右边L的个数sum1和左边R的个数sum2,min(sum1,sum2)就是ans
#include
#include
#include
using namespace std;
#define MAX 100005
char str[MAX];
int main()
{
int t;
int n,m,sum1,sum2;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
scanf("%s",str+1);
sum1=0;
sum2=0;
for(int i=m;i1;i--)
if(str[i]=='R')
sum2++;
printf("%d\n",min(sum1,sum2));
}
return 0;
}
考点:暴力+思维
思路: 题意就是给你三视图,让你求体积。数据中给出了该图形的三视图,若还原的立体图形中,某一位有是实体,在三视图中,三个位置都应该出现过。所以此时暴力枚举每个小块,如果都为1,那么就ans++;这样就可以不重不漏的暴力出答案,这题数据规模也很小,只有100,适应暴力。难点更多的应该在英文理解上。
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N = 105;
int a[N][N], b[N][N], c[N][N];
int main(){
int A,B,C;
while(scanf("%d%d%d",&A,&B,&C)!=EOF){
fo(i,1,A){
fo(j,1,B){
cin>>a[i][j];
}
}
fo(i,1,B){
fo(j,1,C){
cin>>b[i][j];
}
}
fo(i,1,C){
fo(j,1,A){
cin>>c[i][j];
}
}
int ans = 0;
fo(i,1,A){
fo(j,1,B){
fo(k,1,C){
if(a[i][j]&&b[j][k]&&c[k][i]){
ans++;
}
}
}
}
cout<
图论 最短路 dijkstra+堆优化
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N = 1005,M=N*4;
const long long mod = 998244353;
int head[N],Next[M],ver[M],edge[M],tot;
void add(int x, int y, int z){
ver[++tot]=y,edge[tot]=z;
Next[tot]=head[x], head[x]=tot;
}
ll d[N];
bool vis[N];
int D[N];
void dij(int st){
memset(d, 0x3f, sizeof(d));
memset(vis, 0, sizeof(vis));
memset(D, 0, sizeof(D));
priority_queue > q; // 这个要注意
q.push({0,st});
d[st] = 0;
while(q.size()){
int x = q.top().second;q.pop();
if(vis[x])continue;
vis[x] = 1;
for(int i=head[x]; i; i=Next[i]){
int y = ver[i], w = edge[i];
if(d[x] + w < d[y]){
d[y] = d[x] + w;
if(x==st)D[y]=0;
else D[y] = max(D[x], x);
q.push({-d[y], y});
}else if(d[x] + w == d[y]){
int tmp = 0;
if(x==st)tmp = 0;
else tmp = max(x, D[x]); // 到达x的必要D[x]
if(tmp < D[y]){ // 可以有更好的选择
D[y] = tmp;
q.push({-d[y], y});
}
}
}
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
memset(head, 0, sizeof(head));
tot = 0;
int n, m, x, y, z;
scanf("%d %d",&n,&m);
fo(i,1,m){
scanf("%d%d%d", &x, &y, &z);
add(x,y,z);
add(y,x,z);
}
ll ans = 0;
fo(i,1,n){
dij(i);
fo(j,1,n){
ans = (ans+D[j])%mod;
}
}
printf("%lld\n",ans);
}
return 0;
}
三维区间dp,dp[i][j][k]表示以i为开头j为结尾的区间分为k份需要的最少花费,dp[i][j][k]=min(dp[i][j][k],dp[i][p][k-1]+dp[p+1][j][1]),dp[i][j][1]=dp[i][j][k]+sum[j]-sum[i-1](k>=l&&k<=r)
#include
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n,L,R,a[105],sum[105];
int dp[105][105][105],inf = 0x3f3f3f3f;
int main(){
while(scanf("%d%d%d",&n,&L,&R)!=EOF){
fo(i,1,n){
scanf("%d",&a[i]);
sum[i] = sum[i-1] + a[i];
}
memset(dp, 0x3f, sizeof(dp));
fo(i,1,n)dp[i][i][1]=0;
for(int r=1; r<=n; r++){ // 区间长度
for(int i=1; i+r-1<=n; ++i){
int j = i+r-1;
dp[i][j][r] = 0; // 无合并
for(int k=r; k>=1; k--){ // 枚举堆数
if(k==1){
for(int z=L; z<=R; z++){
dp[i][j][1] = min(dp[i][j][1], dp[i][j][z]+sum[j]-sum[i-1]);
}
}else{
for(int z=i; z
考点:字符串 manacher马拉车算法
题意:给定n给整数,求最长回文串,并且前缀非递减,后缀非递增
题解:套manacher模版
#include
#include
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N=1e5+5;
int T,n,a[N];
int Ma[N*2],Mp[N*2],ans;
int Manacher(int a[]){
int l = 0;
Ma[l++]=1;
Ma[l++]=1000;
fo(i,1,n){
Ma[l++]=a[i];
Ma[l++]=1000;
}
Ma[l]=2;
int mx=0,id=0;
for(int i=0; ii?min(Mp[2*id-i],mx-i):1;
int last = Ma[i];
while(Ma[i+Mp[i]]==Ma[i-Mp[i]] && (Ma[i+Mp[i]]==1000||Ma[i+Mp[i]]<=last)){
if(Ma[i+Mp[i]]!=1000)last=Ma[i+Mp[i]];
Mp[i]++;
}
if(i+Mp[i]>mx){
mx = i+Mp[i];
id=i;
}
ans = max(ans,Mp[i]);
}
return ans-1;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
fo(i,1,n)scanf("%d",&a[i]);
ans=0;
printf("%d\n",Manacher(a));
}
return 0;
}
这题是很裸的线段树题了,不过线段树代码量长可以考虑用差分or树状数组
这里展示的是差分的做法
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N=1e6+5;
int d[N],n,m;
void add(int l, int r, int x){
d[l] += x;
d[r+1] -= x;
}
int main(){
int t;scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
n++; // 从0开始
add(1,n,1);
int l,r;
fo(i,1,m){
scanf("%d%d",&l,&r);
l++,r++;
add(l,r,-1);
}
int ans = 0;
fo(i,1,n){
d[i] += d[i-1];
if(d[i]>0)ans++;
}
printf("%d\n",ans);
memset(d,0,sizeof(d));
}
return 0;
}
考点:大数类+推规律
大数题建议使用Java或者Python做,其他题首先考虑c++
首先需要知道的知识点:斐波那契数列前n项之和等于F[n+2]-1,不信可以试试?
知道上面的知识点,考场上联想到这规律,就很好推规律了
问题转移成:前b项的和-前a-1项的和,使用上述规律,即(F[b+2]-1)-(F[a+2-1]-1)
所以只需要判断F[b+2]-F[a+1]的奇偶性
写出前几项的奇偶性就能推出啦~~
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int T = in.nextInt();
while(T-->0) {
BigInteger x = in.nextBigInteger().add(BigInteger.valueOf(1));
BigInteger y = in.nextBigInteger().add(BigInteger.valueOf(2));
int a=1,b=1;
if(y.mod(BigInteger.valueOf(3)).equals(BigInteger.valueOf(0)))
b=0;
if(x.mod(BigInteger.valueOf(3)).equals(BigInteger.valueOf(0)))
a=0;
if((a==1 && b==1) || (a==0 && b==0))
System.out.println(0);
else
System.out.println(1);
}
}
}
考点:又是一道数论题
###斐波那契前缀和
因为乘积满足幂加的关系
容易知道要求幂的斐波那契数列
然后要求前n项和可知是斐波那契前缀和
又斐波那契前缀和与与后面第二项的差-1相等
重点是C^D这一项的幂....
观察规律可知是 fa+fb-n
fa为a的幂
fb为b的幂
(f*A*n) = [fib(n), fib(n+1)]下标0开始
n: 1 2 3 4 5 6 7 (以下表示幂)
B 0 1 1 2 3 5 8 13....这行是 Fib...
前缀和 0 1 2 4 7 12 20 sumA(n-1) = f(n+1)-1 = (f*A*n)[1]-1 下标从0开始
A 1 0 1 1 2 3 5 8
前缀和 1 1 2 3 5 8 13 sumB(n-1) = f(n) = (f*A*n)[0]
C^D 0 0 1 2 4 7 12
前缀和 0 0 1 3 7 14 26 sumC(n-1) = sumA(n-1) + sumB(n-1) - n
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
ll a,b,c,d,mod,n,x,MOD;
int q_pow(ll a, ll n){
int ret = 1;
while(n){
if(n&1)ret = ret*a%mod;
a = a*a%mod;
n>>=1;
}
return ret%mod;
}
int phi(int n){
int ans = n;
for(int i=2; i<=sqrt(n); i++){
if(n%i==0){
ans = ans/i*(i-1);
while(n%i==0)n/=i;
}
}
if(n>1)ans = ans/n*(n-1);
return ans;
}
void mul(int f[2], int a[2][2]){
int c[2];
memset(c,0,sizeof c);
for(int j=0; j<2; j++){
for(int k=0; k<2; k++){
c[j] = (c[j] + (ll)f[k]*a[k][j])%MOD;
}
}
memcpy(f,c,sizeof(c));
}
void mulself(int a[2][2]){
int c[2][2];
memset(c,0,sizeof(c));
for(int i=0; i<2; i++){
for(int j=0;j<2; j++){
for(int k=0; k<2; k++){
c[i][j] = (c[i][j]+(ll)a[i][k]*a[k][j])%MOD;
}
}
}
memcpy(a,c,sizeof(c));
}
void solve(){
int f[2] = {0,1};
int A[2][2] = {{0,1},{1,1}};
int t = n;
for(;t;t>>=1){
if(t&1)mul(f, A);
mulself(A);
}
// cout<<"fib:"<>a>>b>>c>>d>>mod>>n){
MOD = phi(mod);
solve();
}
return 0;
}
简单的搜索题bfs+哈希,和普通搜索题不一样的是需要用哈希表来代替标记数组
#include
#include
#include
#include
考点:二分答案
二分答案与二分查找类似,二分答案主要通过二分可行解来寻找最优解。
如:有一个可行解x=4 ,那么最优解只存在于4~max(最大可能解)
如果中间值mid = (max+x)/2, mid可行的话,最优解存在于 mid~max
如果mid不可行,最优解存在于4~mid
#include
#include
#include
#define maxn 1000000000
using namespace std;
int l,m,n;
int num[50005];
bool check(int cnt){
int last = 0, sum = 0;
for(int i = 1; i <= m+1; i++){
if(num[i] - num[last] < cnt){
sum++;
}else{
last = i;
}
}
if(sum <= n)
return 1;
else
return 0;
}
int main(){
int ans;
scanf("%d %d %d",&l,&m,&n);
int left = 1, right = l;
for(int i = 1; i <= m; i++){
scanf("%d",&num[i]);
}
num[m+1] = l;
while(left <= right){
int mid = (right-left)/2+left; //防越界
if(check(mid)){ //如果可行
ans = mid;
left = mid+1;
}
else{
right = mid-1;
}
}
printf("%d\n",ans);
return 0;
}
考点:大家最喜欢的并查集,优先队列
题意:有n个人编号从1-n,m对朋友关系,当一个人入场时发现场内没有认识的朋友就会不高兴,首先输出最小不高兴值,然后输出字典序最小的入场顺序使得n个人的不高兴值最小。
这题是比较考思维的,希望大家能给惊喜~~A掉TA!!
思路:要使不高兴值最小,那么当入场一个人p,那么p的朋友要跟着入场,p的朋友的朋友也要跟着入场,这样就能使得不高兴值最小,只有1。很容易想到用并查集判断n个人中有几个不相关的集合,即为最小的不高兴值。为使字典序最小,很容易想到用优先队列维护当前最小可入场的人的编号。注意p进去了并不代表p的朋友的朋友可以进去,必须看到直接的朋友才会高兴,所以每次进去一个人,只把他的所有直接朋友压入优先队列。在每次取优先队列的头元素时要注意判断剩余集合的最小元素是否有比头元素字典序小的,考虑到这一点我们在连接两个人时优先让字典序比较小的成为父节点。
#include
#include
#include
#include
#include
using namespace std;
const int MAX = 1e6+5;
int n,m,x,y;
int a[MAX],b[MAX],f[MAX];
bool vis[MAX];
vector g[MAX];
int find(int x){
if(f[x]==x)
return x;
return f[x] = find(f[x]);
}
void Merge(int x,int y){
int a = find(x);
int b = find(y);
if(a!=b){
if(a>b)
f[a] = b;
else
f[b] = a;
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
a[i] = i;
f[i] = i;
vis[i] = false;
g[i].clear();
}
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
Merge(x,y);
}
priority_queue, greater > pq;
int t=0,ans=0;
for(int i=1;i<=n;i++)
if(f[i]==i){
pq.push(a[i]);
vis[i] = true;
ans++;
}
while(!pq.empty()){
int u = pq.top();
pq.pop();
b[++t] = u;
for(int i=0;i