校内NOIP模拟简要题解

校内NOIP模拟简要题解

 7.15

T1

简要题意 : 给定一个N*M的矩阵(N,M小于1018),有多少种方案可以使得每行每列乘积都为K,K为1或-1

Solution : 在有解的情况下,显然最后一行和最后一列一定可以调整前面的值为K,所以答案为 2(n-1)(m-1)

显然无解当且仅当N,M不同奇偶,此时答案为0

#include<bits/stdc++.h>

using namespace std;

inline long long read()
{
    long long f = 1 , x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1; 
    }while(ch < '0' || ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0' && ch <= '9');
    return f*x;
} 

const int MOD = 1e9 + 7;

long long n,m;
long long k;

inline long long Pow(long long a, long long b)
{
    long long ans = 1 ,mul = a;
    while(b)
    {
        if(b&1) ans = (ans * mul) % MOD;
        mul = (mul * mul) % MOD;
        b >>= 1;
    }
    return ans % MOD;
}

int main()
{
    freopen("field.in","r",stdin);
    freopen("field.out","w",stdout);
    n = read(),m = read();k = read();
    if((n+m)&1&&k==-1) cout << 0 << endl;
    else printf("%lld\n",Pow(Pow(2,n-1),m-1)%MOD);
    return 0;
}
/* 
2 1 1
2 2 2
2 3 4
*/
View Code

 

T2

简要题意:

 

 

 Solution:显然对于初始值大于i的,往前移一个值就会减一,同理可以考虑小于i的,然后记录一下什么时候大小关系发生改变,模拟一下即可

#include<bits/stdc++.h>

using namespace std;

inline long long read()
{
    long long f = 1 , x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1; 
    }while(ch < '0' || ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0' && ch <= '9');
    return f*x;
} 

const int MOD = 1e9 + 7;
const int MAXN = 1e6 + 10;

int n;
int p[MAXN];
int a[MAXN];

int main()
{
    freopen("mister.in","r",stdin);
    freopen("mister.out","w",stdout);
    n = read();
    long long res = 0;
    long long ans = 0;
    int a1=0,a2=0;
    for(int i = 1; i<=n;i++)
    {
        p[i] = read();
        res += abs(p[i] - i);
        a[(p[i]-i+n)%n]++;
        if(p[i]>i) a1++;
        else a2++;
    }
    ans = res;
    for(int i=1;i<n;i++)
    {
        res += (a2 - a1 - 1);
        res += (p[n-i+1] - 1) - (n - p[n-i+1]);
        a1 = a1 - a[i] + 1;
        a2 = a2 + a[i] - 1;
        if(res < ans)
        {
            ans = res;
        }
    }
    cout << ans << endl;
}
/* 
2 1 1
2 2 2
2 3 4
*/
View Code

T3

简要题意:给定一个序列,求出这个序列所有连续子区间最大值减最小值差值的和

Solution:显然只需要考虑一个数作为最大值和最小值出现的次数即可

维护第i个数左边第一个大于,小于它的数的位置,和右边第一个大于小于它的数的位置即可

代码找不到了

7.16

T1

不大会

T2

依旧不大会

T3

简单期望DP

先贴个代码

#include<bits/stdc++.h>

using namespace std;

inline long long read()
{
    long long f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch<'0'||ch>'9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();    
    }while(ch>='0'&&ch<='9');
    return f*x;    
} 

#define Rg register 

const int MAXN = 500 + 10;
const int MOD = 1e9 + 7;

long long n,m,k;
long long a[MAXN];
long long f[MAXN][MAXN];
long long sum[MAXN][MAXN];

inline long long Pow(long long a ,long long b)
{
    long long ans = 1, mul = a;
    while(b)
    {
        if(b&1) ans = (ans * mul) % MOD;
        mul = mul * mul % MOD;
        b>>=1;
    }
    return ans % MOD;
}

int main()
{
    freopen("kat.in","r",stdin);
    freopen("kat.out","w",stdout);
    n = read(),m = read(),k = read();
    for(Rg int i=1;i<=m;i++) a[i] = read();
    // cout << Pow(m,MOD-2) << endl;
    for(Rg int i=1;i<=m;i++) f[1][i] = Pow(m , MOD-2);
    for(Rg int i=1;i<=m;i++) sum[1][i] = (sum[1][i-1]+f[1][i])%MOD; 
    for(Rg int i=2;i<=k;i++)
    {
        for(Rg int j=1;j<=m;j++)
        {
            f[i][j] = (sum[i-1][j-1] + f[i-1][j]*j%MOD) * Pow(m,MOD-2) % MOD;
            // cout << "f:" << f[i][j] << endl;
            sum[i][j] = (sum[i][j-1] + f[i][j]) % MOD;
        }
    }
    long long ans = 0;
    for(Rg int i=1;i<=m;i++) ans = (ans + f[k][i] * a[i])% MOD;
    printf("%lld\n",ans*(n-k+1)%MOD);
} 
View Code

 

7.17

T1

简要题意 :求1到N的序列中逆序对对数为K的一共有多少个,N,K<=1000

Solution:考虑到如果是在1-N-1的序列中加入一个N则一定不会有末尾为N的逆序对

于是考虑 $ f_{i,j} $ 表示加入到了第i个数有j个逆序对的方案数,显然DP即可,可以前缀和优化

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0' || ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0' && ch <= '9');
    return f*x;
}

const int MOD = 10000;
const int MAXN = 2000 + 10;

int T;
int n,k;
long long f[MAXN][MAXN]; 

inline void init()
{
    f[1][0] = 1;
    for(int i=2;i<=1000 + 5;i++)
    {
        long long res = 0;
        for(int j=0;j<=min(1000 + 5,i*(i-1)/2);j++)
        {
            res = (res + f[i-1][j]) % MOD;
            if(j>=i) res -= f[i-1][j-i],res=(res+MOD)%MOD;
            f[i][j] = res % MOD;
        }
    }
}

int main()
{
    freopen("permut.in","r",stdin);
    freopen("permut.out","w",stdout);
    T = read();
    init();
    while(T--)
    {
        n = read();k = read();
        printf("%d\n",f[n][k]);
    } 
}
View Code

T2

简要题意:

 

 Solution:

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0' || ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0' && ch <= '9');
    return f*x;
}

const int MAXN = 2000 + 10;

int n,q;
int a[MAXN];
int l[MAXN<<1],r[MAXN<<1];
int f[MAXN];
int dp[MAXN][MAXN];

int main()
{
    freopen("beautiful.in","r",stdin);
    freopen("beautiful.out","w",stdout);
    n = read();
    for(int i=1;i<=n;i++) a[i] = read();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=2*n;j++) l[j] =r[j] = -1;
        l[n] = r[n] = 0;
        int res = 0;
        for(int j=i-1;j>=1;j--) 
        {
            if(a[j]<=a[i]) res--;
            if(a[j]>a[i]) res++;
            l[n+res] = i - j;
        }
        res = 0;
        for(int j=i+1;j<=n;j++)
        {
            if(a[j]>=a[i]) res++;
            if(a[j]<a[i]) res--;
            r[n+res] = j - i;
        }
        for(int j=1-i;j<=i-1;j++)
        {
            if(r[n+j]>=0&&l[n-j]>=0)
            {
                f[i] = max(f[i],r[n+j]+l[n-j]+1);    
            }
        }
    }
    for(int i=1;i<=n;i++) dp[i][i] = f[i];
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            dp[i][j] = max(dp[i][j-1],f[j]);
    q = read();
    for(int i=1;i<=q;i++)
    {
        int l = read(),r = read();
        printf("%d\n",dp[l][r]);
    }
}
View Code

T3

 

 Solution:

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0' || ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0' && ch <= '9');
    return f*x;
}

#define Rg register
#define MAXN 500
#define pre(x) x>>8
#define suf(x) x&255

int N;
int a[MAXN + 10][MAXN + 10];
char opt[50];

int main()
{
    freopen("subset.in","r",stdin);
    freopen("subset.out","w",stdout); 
    N = read();
    for(Rg int i=1;i<=N;i++)
    {
        scanf("%s",opt+1);
        int x = read();
        int val;
        if(opt[1]=='d') val=-1;
        else val = 1;
        if(opt[1]=='a'||opt[1]=='d')
        {
            int u = pre(x), v = suf(x) , w = v^255;
            a[u][v] += val;
            for(int S=w;S;S=(S-1)&w) a[u][S|v] += val; // S|v -> father 
        } 
        else
        {
            int u = pre(x) ,v = suf(x);
            long long ans = 0;
            ans += a[0][v];
            for(int S=u;S;S=(S-1)&u) ans += a[S][v];// S -> u son
            printf("%lld\n",ans);
        }
    }
} 
View Code

 

10.30

T1

简要题意:

给定一个有向图,对其中一条边u,v,求u,v不经过该边的最短路
solution:
每次枚举起点,可以O(M)计算最短路和次短路
 

T3

给定一个位数小于1000的数N,重排每位数字,使凑出一个最大的被11整除的数

solution:

11的倍数的数满足奇数位和偶数位和相等

对于一个给定的N,可以直接算出奇数位和和偶数位和

贪心的考虑可以想到从大到小放入奇数位和偶数位,如果放不到奇数位就一点在偶数位

所以DP预处理出每种状态的可行性

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int f = 1 ,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0'||ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0'&&ch <= '9');
    return f*x;
}

const int MAXN = 1000 + 10;

char s[MAXN];
int x[MAXN];
int dp[MAXN][MAXN][11];
int P[MAXN];
bool vis[MAXN];
int col[MAXN],coll;
vector<int>G[2];
int top[2];

int main()
{
    freopen("sort.in","r",stdin);
    freopen("sort.out","w",stdout);
    scanf("%s",s+1);
    int len = strlen(s+1);
    int sum = 0;
    for(int i=1;i<=len;i++) x[i] = s[i] - '0',sum = (sum  + x[i]) % 11;
//    P[0] = 1;for(int i=1;i<=len;i++) P[i] = (P[i-1] * 10) % 11;
    sum %= 11;
    sort(x+1,x+len+1);
    int res = (len+1)/2;
    memset(dp,0,sizeof(dp));
    dp[0][0][0] = 1;
    for(int i=1;i<=len;i++)
    {
        //cout << x[i] << endl;
        for(int j=0;j<=min(res,i);j++)
        {
            for(int k=0;k<=10;k++)
            {
            //    if(i <= 2) cout << i << " " << j << " " << dp[1][0][10] << endl;
                if(j > 0) dp[i][j][k] = dp[i][j][k]|dp[i-1][j-1][(k-x[i]+11)%11];
                dp[i][j][k] = dp[i][j][k]|dp[i-1][j][k];
            }
        }
    }
    if(sum & 1) sum += 11;
    int cur = sum / 2;coll = 1;
//    cout << cur << endl;
    int sum_o = 0,sum_e = 0;
    int cur_o = 0,cur_e = 0;
//    cout << cur << endl;
    int res_o = res,res_e = len/2;
//    cout << dp[len-1][res_o-1][(cur - x[len] + 11) % 11] << endl;
    for(int i=len;i>=1;i--)
    {
        if(coll == 1)
        {
            if(res_o < cur_o + 1)
            {
                while(i>=1) col[i] = 0,i--;
                continue;
            }
            while(res_o>=cur_o+1&&i>=1&&dp[i-1][res_o-cur_o - 1][(cur - sum_o + 11 -x[i]+11)%11] == 0) sum_e += x[i],sum_e %= 11,cur_e++,col[i] = 0,i--;
            if(!i) break;
        //    cout << i << endl;
            col[i] = 1;sum_o += x[i];sum_o %= 11;cur_o++;coll^=1;
        }
        else
        {
            if(res_e < cur_e + 1)
            {
                while(i>=1) col[i] = 1,i--;
                continue;
            }
        //    cout << i-1 << " " << res_e - 1 << " " << (cur - x[i] + 11) % 11 << endl;
        //    return 0;
        //    cout << dp[i-1][res_e-cur_e - 1][(cur - sum_e + 11-x[i]+11)%11] << endl;
            while(res_e>=cur_e+1&&i>=1&&dp[i-1][res_e-cur_e - 1][(cur - sum_e + 11-x[i]+11)%11] == 0) sum_o += x[i],cur_o++,col[i] = 1,i--,sum_o %= 11;
            if(!i) break;
            col[i] = 0;sum_e += x[i];sum_e %= 11;cur_e++;coll^=1;            
        }
    }
    //cout << res_e << " " <<res_o << endl;
//    cout << 1 << endl;
    for(int i=len;i>=1;i--) G[col[i]].push_back(i);
//    cout << 1 << endl;
    int curr = 1;
    for(int i=1;i<=len;i++)
    {
        printf("%d",x[G[curr][top[curr]++]]);
        curr^=1;
    }
//    for(int i=len;i>=1;i--) if(vis[i]) printf("%d",x[i]);
//    for(int i=len;i>=1;i--) if(!vis[i]) printf("%d",x[i]);
}

 
View Code

 

posted @ 2020-10-18 20:00  wlzs1432  阅读(134)  评论(0编辑  收藏  举报