平时二十一测

 

 

今天考的真的是惨,和爆零差不多了,果然很不稳定啊

第一题:

其实原根没什么,利用期望的性质就好了:权值*概率;

该怎么求最后的权值?

dp[ i ][ j ]表示选了i个数,凑出来是j的方案数, 很好转移dp[i + 1][j * ai%mod] += dp[ i ][ j ];

但是m的数据范围很明显是log,考虑二进制拆分,dp[ i ][j * k % mod] = dp[ i ][ j ] * dp[ i ][ k ], 利用乘法得到j*k%mod的方案数,但是这样是选了2*i个数,这样翻倍是不是很像快速幂;

把m拆位,然后像快速幂计算就好了;

 

#include<bits/stdc++.h>
using namespace std;
const int M = 1e5 + 5;
#define ll long long
const ll P = 1e9 + 7, Pb = 1e9 + 5;
ll ksm(ll a, ll b, ll P){
    ll ret=1;
    for(;b;b>>=1,a=a*a%P)
        if(b&1)ret=ret*a%P;
    return ret;
}
ll dp[33][1005], tmp[1005], ans[1005];

int main(){
    freopen("rand.in","r",stdin);
    freopen("rand.out","w",stdout);
    int n, m, mod;
    scanf("%d%d%d", &n,&m, &mod);
    for(int i = 1; i <= n; i++){
        int x;
        scanf("%d", &x);
        dp[0][x] ++;
    }
    ll Ans = 0;
    int logm = log2(m);
    for(int i = 1; i <= logm; i++)
        for(int j = 1; j < mod; j++)
            for(int k = 1; k < mod; k++){
                dp[i][k * j % mod] = (dp[i][k * j % mod] + dp[i - 1][k] * dp[i - 1][j] % P) % P;
            }
    ans[1] = 1;    
    for(int i = 0; i <= logm; i++)
        if(m & (1<<i)){
            memset(tmp, 0, sizeof(tmp));
            for(int j = 1; j < mod; j++)    
                for(int k = 1; k < mod; k++)
                    tmp[k * j % mod] = (tmp[k * j % mod] + ans[j] * dp[i][k] % P) % P;
            for(int j = 1; j < mod; j++ )ans[j] = tmp[j];
        }
    for(int i = 1; i < mod; i++) Ans = (Ans + ans[i] * i % P) % P;
    ll t = ksm(n, m, P);
    t = ksm(t, 1e9 + 5, P);
    Ans = Ans * t % P;
    printf("%lld\n", Ans);
}
View Code

 

 

 

第二题:

发现同行间,同列间的差值一定;

这个限制可以用带权并查集解决,判断合法;

处理非负数,可以用众多儿子推出某一行的最小值,然后选择儿子通向父亲边权最大的一条边,就可以得到儿子的最小值,判断>=0;

 

#include<bits/stdc++.h>
using namespace std;
const int M = 1e5 + 5;

int fax[M], fay[M], rex[M], rey[M], dl[M], dx[M];

struct node{int x, y, w;}g[M];
bool cmp1(node A, node B){return A.x < B.x;}
bool cmp2(node A, node B){return A.y < B.y;}

int find_x(int x){
    if(x == fax[x]) return x;
    int f = fax[x];
    fax[x] = find_x(fax[x]);
    rex[x] += rex[f];
    return fax[x];
}
int find_y(int x){
    if(x == fay[x]) return x;
    int f = fay[x];
    fay[x] = find_y(fay[x]);
    rey[x] += rey[f];
    return fay[x];
}
bool union_x(int w, int f, int son){
    int fx = find_x(son), fy = find_x(f);
    if(fx == fy && rex[son] != rex[f] + w) return 0;
    fax[fx] = fy, rex[fx] = w + rex[f] - rex[son];
    return 1; 
}
bool union_y(int w, int f, int son){
    int fx = find_y(son), fy = find_y(f);
    if(fx == fy && rey[son] != rey[f] + w) return 0;
    fay[fx] = fy, rey[fx] = w + rey[f] - rey[son];
    return 1; 
}

bool solve(){
    int R, C, n, x, y, d;
    bool fg = 0;    
    scanf("%d%d%d", &R, &C, &n);
    for(int i = 1; i <= n; i++){
        scanf("%d%d%d",&x,&y,&d);
        g[i] = (node){x, y, d};
        if(d < 0) fg = 1;
    }
    if(fg) return 0;
    memset(dx, 127, sizeof(dx));
    memset(dl, 127, sizeof(dl));
    for(int i = 0; i <= R; i++) fax[i] = i, rex[i] = 0;
    for(int i = 0; i <= C; i++) fay[i] = i, rey[i] = 0;
    sort(g + 1, g + 1 + n, cmp1);
    for(int i = 1; i < n; i++)
        if(g[i].x == g[i + 1].x) 
            if(!union_y(g[i].w - g[i+1].w, g[i].y, g[i+1].y)) return 0;
    sort(g + 1, g + 1 + n, cmp2);
    for(int i = 1; i < n; i++)
        if(g[i].y == g[i + 1].y)
            if(!union_x(g[i].w - g[i+1].w, g[i].x, g[i+1].x)) return 0;
    for(int i = 1; i <= n; i++){
        int fx = find_x(g[i].x);
        dx[fx] = min(dx[fx], g[i].w + rex[g[i].x]);
    }
    for(int i = 1; i <= R; i++){
        int fx = find_x(i);
        dl[fx] = min(dl[fx], -rex[i]);
    }
    for(int i = 1; i <= R; i++)
        if(fax[i] == i && dx[i] + dl[i] < 0) return 0;
    return 1;
}




int main(){
    freopen("then.in","r",stdin);
    freopen("then.out","w",stdout);
    int T;
    scanf("%d", &T);
    while(T--){
        if(!solve())puts("No");
        else puts("Yes");
    }
    //system("pause");
}
View Code

 

 

 

第三题:

是一道真水题,但是我看到题这么长就不想思考了,打了半天的dfs分都不分;

正解贪心:人逃是没有用的,怎么也跑不掉,决策就只有膜了;魔法师:会尽量减小x, y 差值中差值最大的,因为平方的缘故,然后暴力搞就好了

值得一提的是我英文单词又拼错了;

 

#include<bits/stdc++.h>
using namespace std;

int T, A, B, ok;
inline int ab(int a){return a >= 0 ? a : -a;}
int main(){
    freopen("do.in","r",stdin);
    freopen("do.out","w",stdout);
    int x1, y1, x2, y2, c, d;
    scanf("%d%d%d", &T, &A, &B);
    while(T--){
        scanf("%d%d%d%d%d%d", &x1, &y1, &x2, &y2, &c, &d);
        int opt = 0;
        while(1){
            if(d <= 0) {puts("NAIVE");break;}
            if(x1 == x2 && y2 == y1) {puts("SIMPLE");break;}
            if(opt == 0){
                if(c < A)c += B;
                else if(c >= A){
                    int dis = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
                    d -= dis; c -= A;
                    if(d <= 0) {puts("NAIVE");break;}
                }    
                opt = 1;
            }
            else {
                if(opt == 1) opt = 2;
                else opt = 0;    
                int res1 = ab(x1 - x2), res2 = ab(y1 - y2);
                if(res2 > res1) y2 += (y1 > y2 ? 1 : -1);
                else x2 += (x1 > x2 ? 1 : -1);
            }
        }    
    }
    return 0;
}
View Code

 

posted @ 2018-11-01 17:33  Ed_Sheeran  阅读(178)  评论(0编辑  收藏  举报