2019 湖南多校第一场(2018~2019NCPC) 题解
解题过程
开场shl过B,C,然后lfw写J,J WA了以后shl写A,但是因为OJ上空间开小WA了,而不是MLE?,J加了特判过了。之后一直在检查A错哪了,直到qt发现问题改了空间,浪费许多时间,但是拿到A一血,shl和byf推出K,不会写组合数而抄了板子, 但是WA, shl想出E题拿到一血了,byf和 shl以为板子错了,让lfw重写K题
lfw重写K题的时候公式复制了之前的代码,又WA了,lfw看出I题,开始写,然后因为高精度加法时c[i]=a[i]+b[i]而不是c[i]+=a[i]+b[i]导致了没有进位,WA了,shl这段时间一直在调D,WA了2发后拿D一血,lfw最后终于发现K题公式中连续3个int级别的数字相乘,中间没有取模,会爆long long ,改了A了,最后lfw发现I题问题,但是因为spj挂了以为没有A,不过最后还是过了。
A Altruistic Amphibians
题目大意:有n只青蛙想从一个深度为d的井中跳出去,因此青蛙需要叠罗汉。青蛙有3个属性,体重,身高,和跳跃力。叠罗汉唯一一个限制就是每只青蛙身上的青蛙的体重之和不能超过自身的体重。青蛙的跳跃力加上身下的青蛙的身高之和如果严格大于d,青蛙就能跳出去。 n<1e5,体重之和,d<1e8;
题解:考虑使用dp dp[i]表示的是能承重w的最大高度(注意这里是承重,不是下面青蛙的总重量)。 dp前需要将青蛙按体重从大到小排序,因为重的青蛙肯定不能在轻的青蛙上面。 因此转移方程就是dp[j]=max(dp[j],h[i]+dp[w[i]+j])(for j in range[1,wi-1]);时间复杂度 O(n)
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define clr(a,v) memset(a,v,sizeof(a)) 4 typedef long long ll; 5 const int maxn=1e5+10; 6 const int maxm=1e8+10; 7 struct Node{ 8 int l,w,h; 9 operator<(Node b)const {return w>b.w;} 10 } node[maxn]; 11 int n,d,dp[maxm],ans; 12 13 int main() 14 { 15 scanf("%d%d",&n,&d); 16 for(int i=1;i<=n;++i) 17 scanf("%d%d%d",&node[i].l,&node[i].w,&node[i].h); 18 sort(node+1,node+1+n); 19 clr(dp,0); ans=0; 20 for(int i=1;i<=n;++i) 21 { 22 if(dp[node[i].w]+node[i].l>d) ans++; 23 for(int j=node[i].w+1;j<min(node[i].w*2,maxm);++j) 24 dp[j-node[i].w]=max(dp[j-node[i].w],dp[j]+node[i].h); 25 } 26 printf("%d\n",ans); 27 return 0; 28 }
B Baby Bites
题目大意:给定n,和一个带有mumble的序列,mumble可以代表任意数字,问该序列可否能为从1开始的连续的序列。 题解:for循环对数字进行判断即可。 复杂度:O(n)
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define clr(a,v) memset(a,v,sizeof(a)) 4 typedef long long ll; 5 const int INF=0x3f3f3f3f; 6 const int maxn=1e5+10; 7 int n,num; 8 char s[maxn]; 9 int work(char s[]) 10 { 11 int len=strlen(s),x=0; 12 for(int i=0;i<len;++i) x=x*10+s[i]-'0'; 13 return x; 14 } 15 int main() 16 { 17 scanf("%d",&n); 18 bool flag=false; 19 for(int i=1;i<=n;++i) 20 { 21 scanf("%s",s); 22 if(s[0]>='0' && s[0]<='9') 23 { 24 num=work(s); 25 if(num!=i) flag=true; 26 } 27 } 28 if(flag) puts("something is fishy"); 29 else puts("makes sense"); 30 31 return 0; 32 }
C Code Cleanups
题解:每次输入就看现在有了多少垃圾,垃圾数量达到20就进行清理 两次相邻输入之间增加的垃圾数为: 垃圾代码数量*相邻天数之差 输入结束看还有没有垃圾代码没被清理
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define clr(a,v) memset(a,v,sizeof(a)) 4 typedef long long ll; 5 int n,d[400],sum,x,ans,tmp; 6 int main() 7 { 8 scanf("%d",&n); 9 clr(d,0); ans=sum=tmp=0; 10 for(int i=1;i<=n;++i) scanf("%d",&x),d[x]++; 11 for(int i=1;i<=365;++i) 12 { 13 if(d[i]) tmp++; 14 sum+=tmp; 15 if(sum>=20) ans++,sum=0,tmp=0; 16 } 17 if(tmp) ans++; 18 printf("%d\n",ans); 19 return 0; 20 }
D:Delivery Delays
题意:
1000个点,5000条边的无向图,披萨店在1号店.1000份披萨订单,每个订单有下单时间,送达地点,披萨制作出来的时间.你是快递员初始在1号点,每次可以拿无穷多披萨,送完以后返回1号点继续送,送餐的时候要求按照下单顺序送达,求等待时间最长的顾客的最小等待时间.
题解:最小化最大值的问题,我们一般用二分答案再judge的套路进行. 考虑到所有的披萨都必须按照下单时间顺序送达,那么可以想象到最优的方案应该会将披萨序列分成若干小段,每一段都是从1号点出发,拿上该段所有的披萨,然后以最短路的形式,依次将披萨送达,最后回到1点. 对于最短路的处理,我们根据题目数据范围:点数n<=1000,边数m<=5000;我们可以进行n次Dijkstra求出任意两点之间的最短时间( O(n^2log(m)) ). 将序列分成若干段,我们可以考虑DP:dp[i]表示前i个订单已经送达且回到1号点的最短时间; 对于i这个点,将所有j≥i+1 && j<=k的dp[j]全部更新. 定义len(i,j) :表示从1出发,依次经过i,i+1,…,j这些点的最短路径长度.
当用dp[i]来更新dp[j]的时候我们注意到出发时间一定不能小于订单的完成时间 max{t[i+1],t[i+2],...,t[j]} ,因为必须等这些披萨都制作完成后才能出发 并且出发时间也一定不能大于最晚时间(即用ans求出的最晚时间);min{ans+s[i+1]−len[i][i+1],...,ans+s[j]−len[i][j]} ,因为对于每个t,满足i+1≤t≤j ,必然有len(i,t)+st−s[j]≤ans,也即st≤ans−len(i,t)+s[j] s同时满足这两个条件的j才能由i进行转移. 如果最后dp[k]被更新过,那么限制M就是可行的,否则不行.
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define clr(a,v) memset(a,v,sizeof(a)) 4 typedef long long ll; 5 typedef pair<ll,int> pli; 6 const ll INF=0x3f3f3f3f3f3f3f3fll; 7 const int maxn=1010; 8 const int maxm=5010; 9 int n,m,k,ecnt,head[maxn]; 10 ll s[maxn],p[maxn],t[maxn]; 11 ll dis[maxn][maxn],dp[maxn]; 12 struct Edge{ 13 int v,nxt; 14 ll w; 15 } edge[maxm<<1]; 16 17 void addedge(int u,int v,int w) 18 { 19 edge[ecnt].v=v; 20 edge[ecnt].w=w; 21 edge[ecnt].nxt=head[u]; 22 head[u]=ecnt++; 23 } 24 25 void dijkstra(int id,int ss) 26 { 27 clr(dis[id],INF); dis[id][ss]=0; 28 priority_queue<pli,vector<pli>,greater<pli> > pq; 29 pq.push(make_pair(dis[id][ss],ss)); 30 while(!pq.empty()) 31 { 32 ll tmp=pq.top().first; 33 int u=pq.top().second; pq.pop(); 34 if(dis[id][u]<tmp) continue; 35 for(int i=head[u];~i;i=edge[i].nxt) 36 { 37 int v=edge[i].v; 38 if(dis[id][v]>dis[id][u]+edge[i].w) 39 { 40 dis[id][v]=dis[id][u]+edge[i].w; 41 pq.push(make_pair(dis[id][v],v)); 42 } 43 } 44 } 45 } 46 47 bool check(ll ans) 48 { 49 memset(dp,INF,sizeof(dp[0])*(n+2)); 50 dp[0]=0; 51 for(int i=0;i<k;++i) 52 { 53 ll st=dp[i],mlst=INF,d=0; 54 for(int j=i+1;j<=k;++j) 55 { 56 if(j==i+1) d+=dis[1][p[j]]; 57 else d+=dis[p[j-1]][p[j]]; 58 st=max(st,t[j]);mlst=min(mlst,ans-d+s[j]); 59 ll tt=st+d-s[j]; 60 if(tt<=ans && st<=mlst) dp[j]=min(dp[j],st+d+dis[p[j]][1]); 61 else break; 62 } 63 } 64 return (dp[k]<INF); 65 } 66 67 int main() 68 { 69 scanf("%d%d",&n,&m); 70 int u,v; ll w; 71 memset(head,-1,sizeof(int)*(n+2));ecnt=0; 72 for(int i=1;i<=m;++i) 73 { 74 scanf("%d%d%lld",&u,&v,&w); 75 addedge(u,v,w);addedge(v,u,w); 76 } 77 for(int i=1;i<=n;++i) dijkstra(i,i); 78 scanf("%d",&k); 79 for(int i=1;i<=k;++i) scanf("%lld%lld%lld",&s[i],&p[i],&t[i]); 80 ll l=0,r=INF,mid,ans=0; 81 while(l<=r) 82 { 83 mid=l+r>>1; 84 if(check(mid)) ans=mid,r=mid-1; 85 else l=mid+1; 86 } 87 printf("%lld\n",ans); 88 89 return 0; 90 }
题意:我方n人,血量已知,对方m人,血量已知。现在有d点伤害,一点一点扣,每次伤害对所有活着的人的概率相同。问d次伤害后对面全死的概率 题解:首先,因为每个士兵的血量最大为6,且敌我双方的士兵数均为5,因此我们考虑可以用搜索的方法去解决 因为士兵的总血量的状态比较少,因此我们可以考虑用一个12位的long long的每一位去存储每一种血量的个数。每一个12位的ll整型就唯一代表了一种状态。因此我们只需要用记忆化的形式对曾经出现过的结果记进行记录,以达到剪枝的作用。因为我们要记录的是敌军死亡的概率,因此,我们可以优先将敌军的6种血量置于12位ll的高位,这样,当我们访问到的状态值<1000000,则代表已经敌军已经已经死亡,即可直接跳出递归(又一个剪枝)。 最后只需要将相应的概率相乘并相加即为答案。
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int n,m,d; 5 int num[2][10]; 6 map<ll,double> dp; 7 8 ll getnum() 9 { 10 ll ans=0; 11 for(int i=1;i>=0;--i) 12 { 13 for(int j=6;j>=1;--j) ans=ans*10+num[i][j]; 14 } 15 return ans; 16 } 17 18 double dfs(ll nm,int limit) 19 { 20 if(dp.count(nm)) return dp[nm]; 21 //if(!limit) return 0; 22 if(nm<1000000) return 1; 23 if(!limit) return 0; 24 double ans=0; 25 int cnt=0; 26 for(int i=0;i<2;++i) 27 for(int j=1;j<=6;++j) cnt+=num[i][j]; 28 //cout<<cnt<<endl; 29 for(int i=0;i<2;++i) 30 { 31 for(int j=1;j<=6;++j) 32 { 33 if(!num[i][j]) continue; 34 num[i][j]--;num[i][j-1]++; 35 ll k=getnum(); 36 double res=dfs(k,limit-1); 37 dp[k]=res; 38 num[i][j]++;num[i][j-1]--; 39 ans=ans+1.0*num[i][j]/cnt*res; 40 } 41 } 42 return ans; 43 } 44 45 int main() 46 { 47 scanf("%d%d%d",&n,&m,&d); 48 int x; 49 memset(num,0,sizeof(num)); 50 for(int i=1;i<=n;++i) scanf("%d",&x),num[0][x]++; 51 for(int i=1;i<=m;++i) scanf("%d",&x),num[1][x]++; 52 double ans=dfs(getnum(),d); 53 printf("%.8lf\n",ans); 54 55 56 return 0; 57 }
F Firing the phaser
unsolved.
G Game Scheduling
题目大意
有m支队伍,每支队伍有n个选手,让所有的选手和其他组的选手进行一次较量.问怎么安排可以让所有的选手在一轮
中只出现一次.且最多一轮不出现.
解题思路
本题是上述的染色算法的一个简单应用,当两个颜色之间还存在着可以染的颜色时,直接染上即可.当两条边之间不
存在可以染的颜色时,则其中一个点必然是一条cdx路径的末端点,故将那条路径翻转,释放出一种新的颜色即可
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef pair<int,int> pii; 4 const int sz=26*26; 5 int match[sz][sz]; 6 bool vis[sz]; 7 bool col[sz]; 8 int n,m; 9 int get_block(int x) 10 { 11 memset(col,0,sizeof(col)); 12 for(int i=0;i<n*m;i++) col[match[x][i]]=1; 13 for(int i=1;i<n*m;i++) if(!col[i]) return i; 14 return n*m; 15 } 16 int check_conflict(int x,int loc) 17 { 18 for(int i=0;i<n*m;i++) if(match[x][i]==loc) return i; 19 return n*m; 20 } 21 void recol(int x, int y) 22 { 23 int pre_match=get_block(y); 24 int conflict=check_conflict(x,pre_match); 25 memset(vis,0,sizeof(vis)); 26 vis[y] = 1; 27 vector<pii> match_line; 28 match_line.push_back(pii(y,pre_match)); 29 while (conflict!=n*m && !vis[conflict]) { 30 vis[conflict] = 1; 31 y=conflict; 32 pre_match = get_block(y); 33 match_line.push_back(pii(y,pre_match)); 34 conflict = check_conflict(x, pre_match); 35 } 36 if (conflict==n*m) { 37 for(auto t:match_line) { 38 match[x][t.first] = t.second; 39 match[t.first][x] = t.second; 40 } 41 } else { 42 int pre_match_x = get_block(x); 43 int conflict_x=check_conflict(conflict,pre_match_x); 44 match[x][conflict] = pre_match_x; 45 match[conflict][x] = pre_match_x; 46 while (conflict_x!=n*m) { 47 int temp= check_conflict(conflict_x,pre_match); 48 match[conflict][conflict_x] = pre_match; 49 match[conflict_x][conflict] = pre_match; 50 conflict=conflict_x; 51 conflict_x=temp; 52 swap(pre_match_x,pre_match); 53 } 54 recol(x,match_line[0].first); 55 } 56 } 57 int main() 58 { 59 scanf("%d%d",&n,&m); 60 for(int i=0;i<n*m;i++) 61 { 62 for(int j=0;j<n*m;j++) 63 { 64 if(i/n!=j/n&&!match[i][j]) 65 recol(i,j); 66 } 67 } 68 int tot=n*(m-1)*n*m/2; 69 for(int k=1;tot;k++) 70 { 71 for(int i=0;i<n*m;i++) 72 { 73 for(int j=i+1;j<n*m;j++) 74 { 75 if(match[i][j]==k) 76 { 77 tot--; 78 printf("%c%d-%c%d ",'A'+i/n,i%n+1,'A'+j/n,j%n+1); 79 } 80 } 81 } 82 cout<<endl; 83 } 84 }
H House Lawn
参考代码:
1 #include<bits/stdc++.h> 2 #define db double 3 #define ll long long 4 using namespace std; 5 const int maxn=1e6+6,inf=1e9; 6 char str[1005]; 7 struct node 8 { 9 char s[65]; 10 int id,p; 11 bool operator<(const node&t)const{return p==t.p? id<t.id:p<t.p;} 12 }a[105]; 13 void gao(int cur,int &pri,int &c,int &t,int &r) 14 { 15 int n=strlen(str),i=0; 16 pri=c=t=r=0; 17 while(str[i]!=',')i++; 18 i++; 19 while(str[i]!=',') 20 pri=pri*10+str[i++]-'0';i++; 21 while(str[i]!=',') 22 c=c*10+str[i++]-'0';i++; 23 while(str[i]!=',') 24 t=t*10+str[i++]-'0';i++; 25 while(i<n) 26 r=r*10+str[i++]-'0'; 27 } 28 int main() 29 { 30 int e,m,pri,c,t,r,v,n=10080,cnt=0; 31 cin>>e>>m; 32 getchar(); 33 for(int i=1;i<=m;i++) 34 { 35 gets(str); 36 gao(i,pri,c,t,r); 37 v=n/(t+r)*t*c; 38 if(v<e) 39 { 40 int tmp=n%(t+r); 41 db v1=(db(e)-v)/c,v2=tmp-v1; 42 if(v1<=(db)t) 43 if(v1*r<=v2*t)v=e; 44 } 45 if(v>=e) 46 { 47 a[++cnt].p=pri; a[cnt].id=i; 48 int len=strlen(str),j=0; 49 while(str[j]!=',') 50 a[cnt].s[j]=str[j],j++; 51 a[cnt].s[j]='\0'; 52 } 53 } 54 sort(a+1,a+1+cnt); 55 if(cnt==0)puts("no such mower"); 56 else 57 { 58 int i=1; 59 while(1) 60 { 61 printf("%s\n",a[i++].s); 62 if(i>cnt||a[i].p>a[i-1].p)break; 63 } 64 } 65 return 0; 66 }
I Intergalactic Bidding
题目大意:总共有 n 个人,每个人有一个权值,给你一个 S,然后问你这 n 个人能否恰好凑齐 S,如果能请输出所选人的名字。注意:这 n 个人的权值如果按照从大到小排序,那么前一个数一定大于等于后者的两倍。 思路:由于这 n 个人之间的权值有两倍关系,因此我们可以把这 n 个人从大到小排序,然后用 S 依次去减,最后判断 S 是否减为 0。我们可以通过二进制来进行证明这个解法的准确性,因为第 k 大一定比第 k+1 大大两倍第 k+1 大一定比第 k+2 大大两倍第 k+3 大……因此后面的数相加永远也无法构成进位,因此,这样的取法是合理的。由于数据量比较大,因此本题需要采用大数。
参考代码:
1 #include<bits/stdc++.h> 2 #define maxl 2010 3 using namespace std; 4 5 int n,anslen; 6 struct node 7 { 8 string nam; 9 int val[maxl]; 10 }a[maxl]; 11 int s[maxl],sum[maxl],tmp[maxl]; 12 char ch[maxl]; 13 string ans[maxl]; 14 15 inline void getval(int a[]) 16 { 17 int len=strlen(ch+1); 18 a[0]=len; 19 for(int i=1;i<=len;i++) 20 a[i]=ch[len-i+1]-'0'; 21 } 22 23 inline bool cmp(const node &a,const node &b) 24 { 25 if(a.val[0]>b.val[0]) 26 return true; 27 if(a.val[0]<b.val[0]) 28 return false; 29 for(int i=a.val[0];i>=1;i--) 30 { 31 if(a.val[i]>b.val[i]) 32 return true; 33 if(a.val[i]<b.val[i]) 34 return false; 35 } 36 return false; 37 } 38 39 inline void prework() 40 { 41 scanf("%d",&n); 42 scanf("%s",ch+1); 43 getval(s); 44 for(int i=1;i<=n;i++) 45 { 46 cin>>a[i].nam; 47 scanf("%s",ch+1); 48 getval(a[i].val); 49 } 50 sort(a+1,a+1+n,cmp); 51 } 52 53 inline void add(int a[],int b[],int c[]) 54 { 55 int len=max(b[0],c[0]); 56 for(int i=1;i<=len;i++) 57 { 58 a[i]+=b[i]+c[i]; 59 if(a[i]>=10) 60 a[i]-=10,a[i+1]+=1; 61 } 62 if(a[len+1]>0) 63 len++; 64 a[0]=len; 65 } 66 67 inline bool nomore(int a[],int b[]) 68 { 69 if(a[0]<b[0]) 70 return true; 71 if(a[0]>b[0]) 72 return false; 73 for(int i=a[0];i>=1;i--) 74 { 75 if(a[i]<b[i]) 76 return true; 77 if(a[i]>b[i]) 78 return false; 79 } 80 return true; 81 } 82 83 inline bool eq(int a[],int b[]) 84 { 85 if(a[0]!=b[0]) 86 return false; 87 for(int i=1;i<=a[0];i++) 88 if(a[i]!=b[i]) 89 return false; 90 return true; 91 } 92 93 inline void mainwork() 94 { 95 for(int i=1;i<=n;i++) 96 { 97 memset(tmp,0,sizeof(tmp)); 98 add(tmp,sum,a[i].val); 99 if(nomore(tmp,s)) 100 { 101 memset(sum,0,sizeof(sum)); 102 for(int j=0;j<=tmp[0];j++) 103 sum[j]=tmp[j]; 104 ans[++anslen]=a[i].nam; 105 } 106 } 107 if(!eq(sum,s)) 108 anslen=0; 109 } 110 111 inline void print() 112 { 113 printf("%d\n",anslen); 114 if(anslen!=0) 115 { 116 for(int i=1;i<=anslen;i++) 117 cout<<ans[i]<<endl; 118 } 119 } 120 121 int main() 122 { 123 prework(); 124 mainwork(); 125 print(); 126 return 0; 127 }
J jumbled String
题目大意:给你四个数 a,b,c,d,要你构造一个 01 串 s 满足以下条件:1. 有 a 种方案使得从 s 中任取两个字符,保持相对顺序恰好为 00;2. 有 b 种方案使得从 s 中任取两个字符,保持相对顺序恰好为 01;3. 有 c 种方案使得从 s 中任取两个字符,保持相对顺序恰好为 10;4. 有 d 种方案使得从 s 中任取两个字符,保持相对顺序恰好为 11;思路:由于是任取两个,因此我们可以考虑组合数,由 C(n,2)=a,C(m,2)=d 我们可以解出 0 的个的个数 m,注意需要单独处理 a(d)=0 的情况,因为当 a(d)=0 且(b != 0 || c != 0)时我们可以发要有一个 0 和 1。容易发现当 n * m != b + c 时是无法构造的,证明:我们先将所有的 1 放到最左边,0 放边,然后我们前移一个 0,当这个 0 没穿过一个 1 时 10 个数减少一个,01 个数增加一
1 #include<bits/stdc++.h> 2 #define maxl 1000010 3 4 long long a,b,c,d,x,y,ans,n; 5 bool flag; 6 char ch[maxl]; 7 8 inline long long find(long long sum) 9 { 10 long long l=1,r=2*sum,mid; 11 while(l+1<r) 12 { 13 mid=(l+r)>>1; 14 if(mid*(mid-1)/2<=sum) 15 l=mid; 16 else 17 r=mid; 18 } 19 if(l*(l-1)/2==sum) 20 return l; 21 else if(r*(r-1)/2==sum) 22 return r; 23 else 24 { 25 flag=false; 26 return 0; 27 } 28 } 29 30 inline void prework() 31 { 32 flag=true; 33 scanf("%lld%lld%lld%lld",&a,&b,&c,&d); 34 if(a==0 && b==0 && c==0 && d==0) 35 { 36 x=1;y=0;return; 37 } 38 if(a==0 && d==0 && (b+c)>0) 39 { 40 x=1;y=1;return; 41 } 42 if(a==0 && d>0) 43 { 44 y=find(d); 45 if(b+c>0) 46 x=1; 47 else 48 x=0; 49 return; 50 } 51 if(a>0 && d==0) 52 { 53 x=find(a); 54 if(b+c>0) 55 y=1; 56 else 57 y=0; 58 return; 59 } 60 x=find(a); 61 y=find(d); 62 } 63 64 inline void mainwork() 65 { 66 n=x+y; 67 if((a+b+c+d)!=n*(n-1)/2) flag=false; 68 if(!flag) return; 69 long long cnt0=x,cnt1=y,sumb=0,sumc=0; 70 for(int i=1;i<=n;i++) 71 if(sumb+cnt1<=b) 72 { 73 ch[i]='0'; 74 cnt0--; 75 sumb+=cnt1; 76 } 77 else 78 { 79 ch[i]='1'; 80 cnt1--; 81 sumc+=cnt0; 82 } 83 if(sumb!=b && sumc!=c) 84 flag=false; 85 } 86 87 inline void print() 88 { 89 if(!flag) 90 puts("impossible"); 91 else 92 { 93 for(int i=1;i<=n;i++) 94 printf("%c",ch[i]); 95 } 96 } 97 98 int main() 99 { 100 prework(); 101 mainwork(); 102 print(); 103 return 0; 104 }
K King's color
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define int long long 4 5 const int mod=1e9+7; 6 const int maxn=3005; 7 8 int n,k; 9 long long ck[maxn],jc[maxn],inv[maxn]; 10 11 long long qp(long long a,long long b) 12 { 13 long long ans=1,cnt=a; 14 while(b) 15 { 16 if(b&1) 17 ans=ans*cnt%mod; 18 cnt=cnt*cnt%mod; 19 b>>=1; 20 } 21 return ans; 22 } 23 void get_ck() 24 { 25 jc[0]=1; 26 for(int i=1;i<maxn;i++) 27 jc[i]=jc[i-1]*i%mod; 28 inv[maxn-1]=qp(jc[maxn-1],mod-2); 29 for(int i=maxn-2;i>=0;i--) 30 inv[i]=inv[i+1]*(i+1)%mod; 31 ck[0]=1; 32 long long fz=1,fm=1; 33 for(int i=1;i<=k;i++) 34 { 35 fz=fz*(k-i+1)%mod; 36 ck[i]=fz*inv[i]%mod; 37 } 38 } 39 long long solve(int n,int k) 40 { 41 long long ans=0; 42 long long flag=1; 43 for(int i=k;i>=2;i--,flag=-flag) 44 { 45 ans=((ans+(1ll*flag*ck[i]*i%mod)*qp(i-1,n-1)%mod)%mod+mod)%mod; 46 } 47 return ans; 48 } 49 int32_t main() 50 { 51 //freopen("K.in","r",stdin); 52 //freopen("K.out","w",stdout); 53 int x; 54 scanf("%lld%lld",&n,&k); 55 get_ck(); 56 for(int i=1;i<n;i++) scanf("%lld",&x); 57 printf("%lld\n",solve(n,k)); 58 return 0; 59 }
%lfw