套题整理 Orz DXY

本文精选了多个算法竞赛题目并提供了详细的解决方案,包括最长上升子序列、数学问题、图论问题等,涵盖了DP、数学、图论等多个算法领域。

弱弱的DXY

 

题目描述

DXY太弱了,以至于他已经不知道要如何解决调整一个数列的使得他变成一个严格上升序列。

输入格式

第 1 行,1 个整数 N

第 2 行,N 个整数 A1,A2,...,AN

输出格式

1 个整数,表示最少需要修改的多少个数字,使得数列变成单调上升的序列。

样例输入

3

1 3 2

样例输出

1

数据:

对于50%的数据:N<=1000

对于100%的数据:N<=100000

保证所有输入整数<=2^63-1


 由于数据比较弱所以可以直接写成最长上升子序列然后n-f[n]骗骗分(大雾)

正解的话是把位置i上的数字减去i,做不下降子序列就好了,不过普通dp会T要找nlogn的做法QAQ

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<algorithm>
 7 #define LiangJiaJun main
 8 #define INF 1999122700
 9 using namespace std;
10 int a[100004];
11 int unset[100004],n;
12 int cnt=0;
13 int erfen(int x){
14     int l=0,r=n,ans=0;
15     while(l<=r){
16         int mid = (l+r) >> 1;
17         if(unset[mid]>x)r=mid-1;
18         else{
19             ans = mid;
20             l = mid + 1;
21         }
22     }
23     return ans;
24 }
25 int LiangJiaJun(){
26     freopen("loser.in","r",stdin);freopen("loser.out","w",stdout);
27     scanf("%d",&n);
28     for(int i=1;i<=n;i++){
29         scanf("%d",&a[i]);
30         a[i]-=i;
31     }
32     for(int i=0;i<=n+1;i++)unset[i]=INF;
33     unset[1]=a[1];unset[0]=-INF;
34     for(int i=2;i<=n;i++){
35         int x=erfen(a[i])+1;
36         unset[x]=min(a[i],unset[x]);
37     }
38     for(int i=1;i<=n;i++)if(unset[i]!=INF)cnt=i;
39     cout<<n-cnt<<endl;
40     fclose(stdin);fclose(stdout);
41     return 0;
42 }

 hint:

不减i的话你看看这个数据1   2   3  2   2   2    2    4     5
减去i如果是不下降就说明那些在不下降序列上的数已经符合他们在数列中的位置,不需要修改了 

数学(math.cpp)

DXY的数学很差。。。

对于所有1<=i<=N求(2^i – i^2)能被7整除的个数。(N<=1000000)

 

样例输入:

      3

样例输出:

1

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define LiangJiaJun main
 5 using namespace std;
 6 int kk[4]={2,4,1},ans=0;long long n;
 7 int LiangJiaJun(){
 8     cin>>n;
 9     for(long long i=1;i<=n;i++){
10         long long x=( kk[ (i-1)%3LL ] + 7LL - ((i*i)%7LL) ) %7LL ;
11 //        cout<<i<<" "<<(i-1)%3<<" "<<((1<<i))%7<<" "<<kk[ (i-1)%3LL ]<<endl;
12         if(x==0){
13             ++ans;
14         }
15     }
16     cout<<ans<<endl;
17     return 0;
18 }

考虑到N可能很大,模拟一下2^i的情况,可以得到kk数组

+7LL有两个点

1.7默认是int,LL后缀默认long long不会溢出

2.7防止取余出现负数

由于都是对7取模,我们可以分步取模

发现2^i对7取模有规律,只要i^2对7取模与其相等就得解

面包(bread.cpp)

     DXY想在一些城市之间开一家面包店。

面包店必须要和小麦店连通,但是这些城市中有小麦店的城市只有K个,很坑的是DXY不喜欢在有小麦店的城市开面包店。一共有n个城市,m条双向路径,K个城市有小麦店。求面包店和小麦店的最短距离是多少。(不能开店的话输出-1)

第一行:n,m,k

第二行到第m+1行,m条路径,u,v,w(表示从u城市到v城市有一条长度为w的边)

第三行一共k个数,表示有小麦店的城市的编号。

样例:

     输入:

5 4 2
1 2 5
1 2 3
2 3 4
1 4 10
1 5

     输出:

3

 

 

输入:

3 1 1
1 2 3
3

     输出:

-1

代码

枚举每一条边(其实枚举小麦店的边就可以),检查是否成立,得到最小值,还要什么超时的最短路

只考虑一条边的原因,1条边+1条边>1条边的长度 

上个 @萌萌的代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 #define maxn 100005
 7 #define qaq 2000022800
 8 using namespace std;
 9 
10 int ans=qaq;
11 int n,m,k;//<=100000
12 int xiaomai;
13 int f[maxn];
14 int QAQ[maxn][3];
15 
16 int main()
17 {
18     memset(f,0,sizeof(f));
19     cin>>n>>m>>k;
20     for(int i=1;i<=m;++i)
21     {
22         scanf("%d%d%d",&QAQ[i][0],&QAQ[i][1],&QAQ[i][2]);//A B W
23     }
24     for(int i=1;i<=k;++i)
25     {
26         scanf("%d",&xiaomai);
27         f[xiaomai]=1;
28     }
29     for(int i=1;i<=m;++i)
30     {
31         if(f[QAQ[i][0]]!=f[QAQ[i][1]])
32         {
33             ans=min(ans,QAQ[i][2]);
34         }
35     }
36     if(ans==qaq)puts("-1");
37     else printf("%d\n",ans);
38     return 0;
39 }
画风太萌不敢看
 
 

孪生蜘蛛

http://codevs.cn/problem/1020/

代码详见这里:http://www.cnblogs.com/radiumlrb/p/5823169.html

 

间隙妖怪(gap.cpp/c/pas)

题目描述:

八云紫是幻想乡的间隙妖怪。她喜欢和八云橙玩一个叫做翻转的游戏。具体规则如下,八云紫对一个长度为N字符串做M次翻转操作,每次操作给定一个X,八云紫将X到N-X之间的字符串翻转。她最喜欢的就是在做M次操作之前询问八云橙这个字符串会变成什么样。然而愚钝的橙一般是答不出来的。为了让橙不在紫妈面前丢脸,你能够帮帮她吗?

输入数据:

第一行:一个字符串(即原字符串)

第二行:一个整数M,表示有M次操作

第三行:M个整数,表示每次操作的X

输出数据:

一个字符串,表示M次操作之后的字符串。

输入样例:

abcdef
1
2

输出样例:

aedcbf

 

 

数据范围:

对于50%数据:M<=5000,字符串长度<=5000

对于100%数据:M<=200000,字符串长度<=200000

代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #define inf 0x3f3f3f3f
 6 using namespace std;
 7 int len,n,a[300005];
 8 //n<1 ???
 9 char s[300005],p[300005];
10 int main(){
11     freopen("gap.in","r",stdin);freopen("gap.out","w",stdout);
12     scanf("%s",s+1);
13     len=strlen(s+1);
14     scanf("%d",&n);
15     for(int i=1;i<=len;i++)p[i]=s[i];
16     for(int i=1;i<=n;i++){
17         int x;
18         scanf("%d",&x);
19         x=min(x,len-x+1);
20         a[x]++;
21     }
22     int q=0;
23     for(int i=1;i<=len/2+1;i++){
24         q+=a[i];
25         if(q%2==0){
26             s[i]=p[i];
27             s[len-i+1]=p[len-i+1];
28         }
29         else{
30             s[i]=p[len-i+1];
31             s[len-i+1]=p[i];
32         }
33     }
34     for(int i=1;i<=len;i++)printf("%c",s[i]);
35     printf("\n");
36     fclose(stdin);
37     fclose(stdout);
38     return 0;
39 }

两次反转就不用重复反转

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #define inf 0x3f3f3f3f
 6 using namespace std;
 7 int len,n,luo[300005],a[300005];
 8 //n<1 ???
 9 char str[300005];
10 int main(){
11     freopen("gap.in","r",stdin);
12     freopen("gap.out","w",stdout);
13     scanf("%s",str+1);
14     len=strlen(str+1);
15     scanf("%d",&n);
16     if(n<1) {
17         for(int i=1;i<=len;i++) printf("%c",str[i]);
18         puts("");
19         return 0;
20     }
21     
22     for(int i=1;i<=n;i++){
23         int x=1;
24         scanf("%d",&x);
25         
26         if(luo[x]==0) luo[x]=1;//两次的不用重复计算 
27         else luo[x]=0;
28     }
29     
30     for(int i=1;i<=n/2;i++){//应该为i<=len/2 
31         if(luo[i]==1&&luo[len-i+1]==1) luo[i]=luo[len-i+1]=0;//左右两次的不用重复计算 
32         if(luo[i]==0&&luo[len-i+1]==1) swap(luo[i],luo[len-i+1]);//都归到数组左边 
33     }
34     
35     //想不到好算法 
36     int point=1;
37     while(point<=len/2){//标记需要交换的元素 
38         if(luo[point]==1){
39             int i=point+1;//如果该元素需要标记,则向右扫,
40                           //直到右边出现需要交换的首位 ,将该首位置零  
41             while(i<=len/2){
42                 if(luo[i]==1){
43                     luo[i]=0;
44                     break;
45                 }
46                 else luo[i]=1;
47                 point=i++;
48             }
49         }
50         point++;
51     }
52     
53     for(int i=1;i<=len/2;i++)
54         if(luo[i]==1)
55             swap(str[i],str[len-i+1]);
56     
57     for(int i=1;i<=len;i++) printf("%c",str[i]);//out 
58     puts("");
59     return 0;
60 }
错误代码

命名规范一点儿,Line30致命错误

 

 

无聊的gcd(gcd.c/cpp/pas)

话说出题人不会被查水表吧。

简单的问题描述:从N个正整数里面取出K个数的最大公因数最小是多少。(请将答案乘上k之后输出哦,谢谢合作。)

输入格式

第一行两个正整数N,K。

第二行n个正整数

输出格式

输出一个正整数表示最大的最大公因数。

样例输入

3 1

1 2 3

样例输出

    3

数据说明

对于30%的数据,保证k≤n≤20。

对于50%的数据,保证输入中所有数小于5000。

对于100%的数据,保证输入中所有数小于500000,k≤n。

代码

 1 #include <cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 const int Maxn = 40;
 5 
 6 int a[Maxn],n,k,ans=0;
 7 
 8 int gcd(int a,int b) 
 9 {
10     return b ? gcd(b,a%b) : a;
11 }
12 
13 int max(int a,int b) 
14 {
15     return a < b ? b : a ;
16 }
17 
18 int main() 
19 {
20     scanf("%d%d",&n,&k);
21     for(int i=0;i<n;++i)scanf("%d",&a[i]);//读入 
22     for(int i=1;i<(1<<n);++i) 
23     {
24         int tmp = 0;
25         for(int j=0;j<n;++j) 
26         {
27             if(i&(1<<j))    ++tmp;
28             //tmp表示选了几个数 
29         }
30 //        printf("i = %d : tmp = %d\n",i,tmp);
31         if(tmp==k)//如果选了k个 
32         {
33             tmp=-1;
34             for(int j=0;j<n;++j) 
35             {
36                 if(i&(1<<j)) 
37                 {
38                     if(tmp==-1) tmp=a[j];
39                     else tmp=gcd(a[j],tmp);
40                 }
41             }
42             ans = max(ans,tmp);
43 //            printf("ans : %d\n",ans);
44         }
45     }
46     printf("%d",ans*k);
47     puts("");
48     return 0;
49 } 
不会

转载@gc812

0表示不取 1表示取

用i的二进制表示状态  比如i=10101表示取1,3,5    i=00110表示取3,4

然后for一遍,tmp表示i的二进制当中1的数量
如果1有k个
那么i代表的状态选了k个数

for一遍把i表示的状态取了的数的gcd取出来

最后统计ans

如果i&(1<<j) == 1的话那么i的第j位就是1 

因为1<<j是...001000...的形式存在,所以和 i 与起来,要是 i 这一位是 1 , 就是1,i 这一位是0,就是0

 所以 i&(1<<j) 表示 i 在二进制下的第 j 位

 因为1<<0 = 1 这时候j=0 如果从1存的话就变成1<<1 = 2 那就时间复杂度*2 所以从0开始读

 

因为所有输入的数字都不超过五十万
那么我们就可以开个数组t,记一下每个数字出现的次数
然后枚举答案
判断一个答案是否可行的方法就是遍历t数组
看看所有答案x的倍数的个数是否大于等于k 

 

 

 

虫洞(wormhole.cpp/c/pas) http://poj.org/problem?id=3259

【题目描述】

John在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。John的每个农场有M条小路(无向边)连接着N (从1..N标号)块地,并有W个虫洞(有向边)。其中1<=N<=500,1<=M<=2500,1<=W<=200。 现在John想借助这些虫洞来回到过去(出发时刻之前),请你告诉他能办到吗。 John将向你提供F(1<=F<=5)个农场的地图。没有小路会耗费你超过10000秒的时间,当然也没有虫洞回帮你回到超过10000秒以前。

【输入格式】

* Line 1: 一个整数 F, 表示农场个数。

* Line 1 of each farm: 三个整数 N, M, W。

* Lines 2..M+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条用时T秒的小路。

* Lines M+2..M+W+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条可以使John到达T秒前的虫洞。

【输出格式】

* Lines 1..F: 如果John能在这个农场实现他的目标,输出"YES",否则输出"NO"。

【样例输入】

2

3 3 1

1 2 2

1 3 4

2 3 1

3 1 3

3 2 1

1 2 3

2 3 4

3 1 8

【样例输出】

NO

YES

 

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
struct city{
    int num,d,magic;
}nod[505];//存 magic虫洞 单向边 

city make_city(int num,int d,int magic){
    city a;a.num=num;a.magic=magic;a.d=d;
    return a;
}

struct cmp{
    bool operator()(city a,city b){
        return a.d>b.d;
    }
};

priority_queue<city,vector<city>,cmp > que;
vector<int> e[505],c[505];
int dis[505],vis[505],n,m,w;

void cls(){
    for(int i=1;i<=503;i++){
        e[i].clear();
        c[i].clear();
        
        nod[i].d=0;
        nod[i].magic=0;
        nod[i].num=i;
    }
    n=m=w=0;
    memset(vis,0,sizeof(vis));
    
    priority_queue<city,vector<city>,cmp > temp;
    swap(que,temp);
}

void Dijkstra(){
    memset(dis,0x3f,sizeof(dis));
    que.push(make_city(1,0,nod[1].magic));dis[1]=0;
    while(!que.empty()){
        city now=que.top();que.pop();
        if(vis[now.num]) continue;vis[now.num]=1;
        
        if(now.magic>dis[now.num]){
            puts("YES");return;
        }
        
        for(int i=0;i<e[now.num].size();i++){
            if(dis[now.num]+c[now.num][i]<dis[e[now.num][i]]){
                dis[e[now.num][i]]=dis[now.num]+c[now.num][i];
                que.push(make_city(e[now.num][i],dis[e[now.num][i]],nod[e[now.num][i]].magic));
            }
        }
    }
    puts("NO");return;
}

int main(){
//    freopen("wormhole.in","r",stdin);
//    freopen("wormhole.out","w",stdout);
    int shu=0;
    scanf("%d",&shu);
    for(int bian=1;bian<=shu;bian++){
        
        cls();
        scanf("%d%d%d",&n,&m,&w);
        for(int i=1;i<=m;i++){
            int u=0,v=0,cost=0;
            scanf("%d%d%d",&u,&v,&cost);
            e[v].push_back(u);
            e[u].push_back(v);
            c[u].push_back(cost);
            c[v].push_back(cost);
        }
        for(int i=1;i<=w;i++){
            int u=0,v=0,cost=0;
            scanf("%d%d%d",&u,&v,&cost);
            nod[u].magic=cost;//单向边 
        }
        Dijkstra();
        
    }
    return 0;
}//题意是任意顶点都可以出发
Dijkstra错误代码
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #define INF 0x3f3f3f3f
 6 using namespace std;
 7 struct edge{int from,to,cost;}e[6005];
 8 int N,M,W,p,d[505];
 9 
10 int find_negative_loop(int V,int E){
11     memset(d,0x3f,sizeof(d));
12     
13     for(int i=1;i<=V;i++){
14         for(int j=1;j<=E;j++){
15             edge now=e[j];
16             
17             if(d[now.to]>d[now.from]+now.cost){
18                 d[now.to]=d[now.from]+now.cost;
19                 if(i==V) return 1;
20             }
21             
22         }
23     }
24     return 0;
25 }
26 
27 void add(int from,int to,int cost){
28     e[++p].from=from;
29     e[p].to=to;
30     e[p].cost=cost;
31 }
32 
33 void cls(){
34     for(int i=0;i<=6002;i++){
35         e[i].from=e[i].to=e[i].cost=0;
36     }
37     p=0;
38     N=M=W=0;
39 }
40 
41 int main(){
42 //    freopen("wormhole.in","r",stdin);
43 //    freopen("wormhole.out","w",stdiout);
44     int kk;
45     scanf("%d",&kk);
46     while(kk--){
47         cls();
48         
49         scanf("%d%d%d",&N,&M,&W);
50         for(int i=1;i<=M;i++){
51             int u,v,w;
52             scanf("%d%d%d",&u,&v,&w);
53             add(u,v,w);
54             add(v,u,w);
55         }
56         
57         for(int i=1;i<=W;i++){
58             int u,v,w;
59             scanf("%d%d%d",&u,&v,&w);
60             add(u,v,-w);
61         }
62         
63         if(find_negative_loop(N,p)) puts("YES");
64         else puts("NO");
65     }
66     return 0;
67 }

题意是找负环~

#include <iostream>
#include <cstdio>
#include <vector>
#include <stack>
using namespace std;

#define inf 99999999
#define V 520
#define NE 6000
int n,m,w;
struct node
{
    int v;
    int val;
}E;
vector<node> Node[V+2];
int spfa(int k)
{
    int d[V], cnt[V], vis[V];
    for(int j = 1;j <= n;j ++)
    d[j] = inf,cnt[j] = 0,vis[j] = 0;
    d[k] = 0; vis[k] = 1;cnt[k] = 1;

    stack<int> p;p.push(k);
    while(!p.empty())
    {
        int u = p.top(); 
        p.pop();vis[u] = 0;
        int len = Node[u].size();

        for(int j = 0;j < len;j ++)
        {
            int v = Node[u][j].v;
            int c=Node[u][j].val;
            if(d[v] - c > d[u])
            {
                d[v] = c + d[u];
                if(!vis[v])
                {
                    vis[v] = 1; cnt[v] ++;
                    if(cnt[v] >= n) return 1;
                    p.push(v);
                }
            }
        }
    }
    return 0;
}
int main()
{
    int cs;
    scanf("%d",&cs);
    while(cs--)
    {
        scanf("%d%d%d",&n,&m,&w);
        for(int j = 1;j <= n;j ++)
        Node[j].clear();

        while(m--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            E.v = b; E.val = c;
            Node[a].push_back(E);

            E.v = a; E.val = c;
            Node[b].push_back(E);
        }
        while(w--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            E.v = b;E.val = -c;
            Node[a].push_back(E);
        }
        if(!spfa(1)) puts("NO");
        else   puts("YES");
    }
    return 0;
}
转载SPFA

 注意边可能很多,要开到6000才压得住

5*2500而不是2500,我zz了

a*b(mod.cpp/c/pas)

没错dxy的题目就是这么简单。

输入:

第一行一个数t,表示有t个数据

2到第t+1行,每行三个正整数a,b,c a,b,c<=10^18

输出:对于每组数据输出(a*b%c

 

样例输入:

1

1   2    3

样例输出:

 

2

代码

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 int a[20002],b[20002],c[20002],d[20002],e[20002],k[20002];
  8 int l1,l2,l3,i,code;
  9 int n;
 10 string n1,n2;
 11 
 12 void init(int a[]) {
 13     string s;
 14     int i;
 15     memset(a,0,sizeof(a));
 16     cin >> s;
 17     a[0] = s.length();
 18     for(i=1;i<=a[0];i++) {
 19         a[i]=s[a[0]-i]-48;
 20     } 
 21 }
 22 
 23 void print(int a[]) {
 24     int i;
 25     for(int i=a[0]; i>=1; i--) cout << a[i];
 26     puts("");
 27 }
 28 
 29 void clear(int a[]) {
 30     int i;
 31     for(int i=1;i<=a[0];i++) {
 32         a[i+1]+=a[i]/10;
 33         a[i]%=10;
 34     }
 35     while((a[a[0]]==0) && (a[0]>1)) a[0]--;
 36 }
 37 
 38 int compare(int a[], int b[]) {
 39     int i;
 40     clear(a);
 41     clear(b);
 42     if(a[0]>b[0]) {
 43         return 1;
 44     }
 45     if(a[0]<b[0]) {
 46         return -1;
 47     }
 48     for(i=a[0]; i>=1; i--) {
 49         if(a[i]>b[i]) {
 50             return 1;
 51         }
 52         if(a[i]<b[i]) {
 53             return -1;
 54         }
 55     }
 56     return 0;
 57 }
 58 
 59 
 60 void minus1(int a[], int b[], int c[]) {
 61     int i;
 62     int t[20002];
 63     bool flag = false;
 64     if(compare(a,b)<0) {
 65         memcpy(c,b,sizeof(c));
 66         memcpy(t,b,sizeof(t));
 67         memcpy(b,a,sizeof(b));
 68         flag = true;
 69     } else memcpy(c,a,sizeof(int)*20002);
 70     for(i=1;i<=c[0];i++) {
 71         c[i+1]--;
 72         c[i]+=10-b[i];
 73     }
 74     clear(c);
 75     if(flag) memcpy(b,t,sizeof(b));
 76 }
 77 
 78 void multiply(int a[], int b[], int c[]) {
 79     int i,j;
 80     memset(c, 0, sizeof(int)*20002);
 81     for(i=1; i<=a[0];i++) 
 82         for(j=1;j<=b[0];j++)
 83             c[i+j-1]+=a[i]*b[j];
 84     c[0]=a[0]+b[0];
 85     clear(c);
 86 }
 87 
 88 void divide(int a[], int b[], int c[],int d[]) {
 89     int i,j,p;
 90     memset(c, 0, sizeof(c));
 91     memset(d, 0, sizeof(d));
 92     c[0]=a[0]; d[0]=1;
 93     for(j=a[0]; j>=1;j--) {
 94         d[0]++;
 95         for(p=d[0];p>=2;p--) {
 96             d[p]=d[p-1];
 97         }
 98         d[1]=a[j];
 99         while(compare(d,b)>=0) {
100             c[j]++;
101             minus1(d,b,d);
102         }
103     }
104     clear(c);
105     clear(d);
106 }
107 
108 int main() {
109     freopen("mod.in","r",stdin);
110     freopen("mod.out","w",stdout);
111     scanf("%d",&n);
112     while(n--){
113         memset(a,0,sizeof(a));
114         memset(b,0,sizeof(b));
115         memset(c,0,sizeof(c));
116         memset(d,0,sizeof(d));
117         memset(e,0,sizeof(e));
118         memset(k,0,sizeof(k));
119         
120         init(a);
121         init(b);
122         init(k);
123         multiply(a,b,e);
124         divide(e,k,c,d);
125         print(d);
126     }
127     return 0;
128 }

恶心的高精,说多了都是泪

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 
 6 using namespace std;
 7 
 8 int n;
 9 
10 long long mul(long long a, long long b, long long p) 
11 { // a * b % p;
12     long long ret = 0; 
13     for (int i = 62; ~ i; -- i)//~ >=0
14     ret = (ret + ret) % p, b & (1ll << i) ? ret = (ret + a) % p : 0;
15     return ret % p;
16 }
17 
18 int main()
19 {
20     freopen("mod.in","r",stdin);
21     freopen("mod.out","w",stdout);
22     cin>>n;
23     long long a,b,c;
24     for(int i=1;i<=n;++i)
25     {
26         scanf("%lld%lld%lld",&a,&b,&c);
27         printf("%lld",mul(a,b,c));
28         puts("");
29     }
30     fclose(stdin);fclose(stdout);
31     return 0;
32 }
非常短的std

 思想大概就是把两个数分成几个数的和 然后就能乘了

 

过节(festival.cpp/c/pas

     Dxy帮老师们过教师节的时候需要购买礼物。货架上有n 种礼物,每种礼物有不同的个数。每种礼物有价值和花费两种属性,帮他算出最大可以得到的价值。

Input:

第一行两个数n,m

2n+1行:每行三个数a,b,c,表示一种礼物的个数,花费和价值。

 

Output:

最大可得价值。

 

样例输入:

2  5

1  1  1

2 2 4

样例输出:

 

1

代码

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #define ll long long
 6 using namespace std;
 7 ll num[1000005],w[1000005],v[1000005],f[1000005];
 8 ll n,m;
 9 
10 void zero(ll value,ll weight){
11     for(int i=m;i>=weight;i--){
12         f[i]=max(f[i],f[i-weight]+value);
13     }
14 }
15 
16 void complete(ll value,ll weight){
17     for(int i=weight;i<=m;i++){
18         f[i]=max(f[i],f[i-weight]+value);
19     }
20 }
21 
22 void multi(){
23     for(int i=1;i<=n;i++){
24         if(num[i]*w[i]>m) complete(v[i],w[i]);
25         else{
26             int k=1;
27             while(k<num[i]){
28                 zero(k*v[i],k*w[i]);
29                 num[i]-=k;
30                 k<<=1;
31             }
32             zero(num[i]*v[i],num[i]*w[i]);
33         }
34     }
35 }
36 
37 int main(){
38     freopen("festival.in","r",stdin);
39     freopen("festival.out","w",stdout);
40     scanf("%lld%lld",&n,&m);
41     for(int i=1;i<=n;i++){
42         scanf("%lld%lld%lld",&num[i],&w[i],&v[i]);
43     }
44     
45     multi();
46     
47     ll ans=0;
48     for(int i=1;i<=m;i++){
49         ans=max(ans,f[i]);
50     }
51     printf("%lld\n",ans);
52     return 0;
53 }

多重背包

30                 k<<=1;

Line 30 写成了k<=1;

爆炸了!!!

扫描(scan.cpp/c/pas)

【题目描述】

有一个 1 n 的矩阵,有 n 个正整数。

现在给你一个可以盖住连续的 k 的数的木板。

一开始木板盖住了矩阵的第 1 k 个数,每次将木板向右移动一个单位,直到右端与

n 个数重合。

每次移动前输出被覆盖住的最大的数是多少。

【输入格式】

scan.in 中输入数据

第一行两个数,nk,表示共有 n 个数,木板可以盖住 k 个数。

第二行 n 个数,表示矩阵中的元素。

【输出格式】

输出到 scan.out

n − k + 1 行,每行一个正整数。

i 行表示第 i ~ i + k − 1 个数中最大值是多少。

【样例输入】

5 3

1 5 3 4 2

【样例输出】

5

5

4

【数据规模与约定】

对于 20% 的数据保证:1 n 10^31 k n

对于 50% 的数据保证:1 n 10^41 k n

对于 100% 的数据保证:1 n 2 10^51 k n

 

矩阵中元素大小不超过 10^4

代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ll long long
 6 using namespace std;
 7 ll tr[10000005];
 8 ll n,k,M,tmp;
 9 void query(ll s,ll t){
10     ll ans=0;
11     for(s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1){
12         if(~s&1) ans=max(ans,tr[s^1]);
13         if(t&1)  ans=max(ans,tr[t^1]);
14     }
15     printf("%lld\n",ans);
16 }
17 
18 void change(ll x,ll y){
19     for(tr[x+=M]=y,x>>=1;x;x>>=1)
20         tr[x]=max(tr[x<<1],tr[x<<1|1]);
21 }
22 
23 int main(){
24     freopen("scan.in","r",stdin);
25     freopen("scan.out","w",stdout);
26     scanf("%lld%lld",&n,&k);
27     for(M=1;M<=n+1;M<<=1);
28     for(ll i=1;i<=n;i++){
29         scanf("%lld",&tmp);
30         change(i,tmp);
31     }
32     
33     for(ll i=1;i<=n-k+1;i++){
34         query(i,i+k-1);
35     }
36     return 0;
37 }

zkw线段树,没了?

没了!

DXY的消失

题目描述

给出 N 个点,M 条边的有向图,对于每个点 v,求 D(v) 表示从点 v 出发,能到达的编号最大的点。

 

输入格式

1 行,2 个整数 N,M。 接下来 M 行,每行 2 个整数 Ui,Vi,表示边 ⟨Ui,Vi⟩。点用 1,2,...,N 编号。

 

输出格式

N 个整数 D(1),D(2),...,D(N)

样例输入

4 3

1 2

2 4

4 3

样例输出

4 4 3 4

数据范围

对于 60% 的数据,1 N,M 1000

 

对于 100% 的数据,1 N,M 100000

代码

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<vector>
 6 #define MAX 100005
 7 using namespace std;
 8 vector<int> G[MAX],rG[MAX],vs;
 9 int used[MAX],cmp[MAX],ans[MAX];
10 int V,m;
11 
12 void add(int from,int to){//反向的反向边 
13     G[from].push_back(to);
14     rG[to].push_back(from);
15 }
16 
17 void dfs(int v){
18     used[v]=1;
19     for(int i=0;i<G[v].size();i++){
20         if(!used[G[v][i]]) dfs(G[v][i]);
21     }
22     vs.push_back(v);
23 }
24 
25 void rdfs(int v,int k){
26     used[v]=1;
27     cmp[v]=k;
28     for(int i=0;i<rG[v].size();i++){
29         if(!used[rG[v][i]]) rdfs(rG[v][i],k);
30     }
31     ans[k]=max(ans[k],v);
32     for(int i=0;i<rG[v].size();i++){
33         ans[k]=max(ans[k],ans[cmp[rG[v][i]]]);
34     }
35 }
36 
37 int scc(){
38     memset(used,0,sizeof(used));
39     vs.clear();
40     for(int v=1;v<=V;v++){
41         if(!used[v]) dfs(v);
42     }
43     memset(used,0,sizeof(used));
44     int k=0;
45     for(int i=vs.size()-1;i>=0;i--){
46         if(!used[vs[i]]) rdfs(vs[i],k++);
47     }
48 }
49 
50 int main(){
51     freopen("disappear.in","r",stdin);
52     freopen("disappear.out","w",stdout);
53     scanf("%d%d",&V,&m);
54     for(int i=1;i<=m;i++){
55         int from,to;
56         scanf("%d%d",&from,&to);
57         add(to,from);//反向 
58     }
59     scc();
60     for(int i=1;i<=V;i++)
61         printf("%d ",ans[cmp[i]]);
62     puts("");
63     return 0;
64 }

强联通分量合并+逆序

这个算法详见这里,来自《挑战程序设计竞赛》

 

 

 

转载一个tarjan,Orz DXY

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<stack>
 6 #include<queue>
 7 #include<cstring>
 8 #define LiangJiaJun main
 9 using namespace std;
10 int n,m,cnt,ne,h[100004],h2[100004];
11 int d[100004],scc,belong[100004],kp[100004],dfn[100004],low[100004];
12 int ind[100004];
13 bool inq[100004],vis[100004];
14 stack<int>st;
15 struct edge{
16     int to,next;
17 }e[300004],ed[300004];
18 void insert(int u,int v){
19     e[++ne].to = v;
20     e[ne].next = h[u];
21     h[u] = ne;
22 }
23 void insert2(int u,int v){
24     ed[++cnt].to = v;
25     ed[cnt].next = h2[u];
26     h2[u] = cnt;
27 }
28 void tarjan(int x){
29      vis[x]=inq[x]=1;//cout<<x<<endl;
30      dfn[x]=low[x]=++cnt;
31      st.push(x);
32      for(int i=h[x];i;i=e[i].next){
33          if(!vis[e[i].to]){
34              tarjan(e[i].to);
35              low[x] = min(low[x],low[e[i].to]);
36          }
37          else if(inq[e[i].to]) low[x] = min(low[x],dfn[e[i].to]);
38      }
39      if(low[x]==dfn[x]){
40         //cout<<low[x]<<" "<<dfn[x]<<endl;
41         int now=-1;++scc;
42         while(now!=x){
43             now=st.top();st.pop();
44             kp[scc]=max(now,kp[scc]);
45             inq[now]=0;
46             belong[now]=scc;
47         }
48      }
49 }
50 void rebuild(){
51      cnt=0;
52      for(int i=1;i<=n;i++){
53          for(int j=h[i];j;j=e[j].next){
54              if(belong[i]!=belong[e[j].to]){
55                 insert2(belong[i],belong[e[j].to]);
56                 ++ind[belong[e[j].to]];//cout<<belong[e[j].to]<<endl;
57              }
58          }
59      }
60 }
61 queue<int>q;
62 
63 int LiangJiaJun(){
64     freopen("disappear.in","r",stdin);freopen("disappear.out","w",stdout);
65     scanf("%d%d",&n,&m);
66     for(int i=1;i<=m;i++){
67         int u,v;
68         scanf("%d%d",&u,&v);
69         insert(v,u);
70     }
71     for(int i=1;i<=n;i++) if(!vis[i]) tarjan(i);
72     rebuild();
73     for(int i=1;i<=scc;i++)if(!ind[i])q.push(i);
74 
75     while(!q.empty()){
76         int x=q.front();q.pop();
77         for(int i=h2[x];i;i=ed[i].next){
78             kp[ed[i].to]=max(kp[ed[i].to],kp[x]);
79             --ind[ed[i].to];
80             if(ind[ed[i].to]<=0)q.push(ed[i].to);
81         }
82     }
83     for(int i=1;i<=n;i++) printf("%d ",kp[belong[i]]);cout<<endl;
84     fclose(stdin);fclose(stdout);
85     return 0;
86 }

 

 

转载于:https://www.cnblogs.com/radiumlrb/p/5814774.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值